]> granicus.if.org Git - pdns/commitdiff
refactor PowerDNSLua into a base class plus AuthLua and RecursorLua; add auth lua...
authorPeter van Dijk <peter.van.dijk@netherlabs.nl>
Wed, 20 Jun 2012 10:12:20 +0000 (10:12 +0000)
committerPeter van Dijk <peter.van.dijk@netherlabs.nl>
Wed, 20 Jun 2012 10:12:20 +0000 (10:12 +0000)
git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@2631 d19b8d6e-7fed-0310-83ef-9ca221ded41b

16 files changed:
pdns/Makefile-recursor
pdns/Makefile.am
pdns/common_startup.cc
pdns/dist-recursor
pdns/lua-auth.cc [new file with mode: 0644]
pdns/lua-auth.hh [new file with mode: 0644]
pdns/lua-pdns-recursor.cc [deleted file]
pdns/lua-pdns.cc [new file with mode: 0644]
pdns/lua-pdns.hh [new file with mode: 0644]
pdns/lua-recursor.cc [new file with mode: 0644]
pdns/lua-recursor.hh [moved from pdns/lua-pdns-recursor.hh with 60% similarity]
pdns/packethandler.cc
pdns/packethandler.hh
pdns/pdns_recursor.cc
pdns/powerdns-example-script.lua
pdns/slavecommunicator.cc

index 2d71d3c2a48ec8eecdf0f23cb0ef182b0c964a77..ef3cc0e2197157ec5b1bd86b0dd75cdc704b4ac7 100644 (file)
@@ -18,9 +18,9 @@ PDNS_RECURSOR_OBJECTS=syncres.o  misc.o unix_utility.o qtype.o logger.o  \
 arguments.o lwres.o pdns_recursor.o recursor_cache.o dnsparser.o \
 dnswriter.o dnsrecords.o rcpgenerator.o base64.o zoneparser-tng.o \
 rec_channel.o rec_channel_rec.o selectmplexer.o sillyrecords.o \
-dns_random.o aescrypt.o aeskey.o aes_modes.o aestab.o lua-pdns-recursor.o \
-randomhelper.o recpacketcache.o dns.o reczones.o base32.o nsecrecords.o \
-dnslabeltext.o
+dns_random.o aescrypt.o aeskey.o aes_modes.o aestab.o dnslabeltext.o \
+lua-pdns.o lua-recursor.o randomhelper.o recpacketcache.o dns.o \
+reczones.o base32.o nsecrecords.o
 
 REC_CONTROL_OBJECTS=rec_channel.o rec_control.o arguments.o misc.o \
        unix_utility.o logger.o qtype.o
index a6234266b6a1f0ffa9a0896cf0a78b0f641dd6d8..8eb8f47cd6376a3291d4a7f426cb46aeb50920a7 100644 (file)
@@ -47,7 +47,7 @@ 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 lua-pdns-recursor.cc serialtweaker.cc \
+md5.hh signingpipe.cc signingpipe.hh dnslabeltext.cc lua-pdns.cc lua-auth.cc serialtweaker.cc \
 ednssubnet.cc ednssubnet.hh cachecleaner.hh dnslabel.hh dnslabel.cc
 
 #
@@ -209,7 +209,7 @@ dnswriter.cc dnslabeltext.cc dnswriter.hh dnsrecords.cc dnsrecords.hh rcpgenerat
 base64.cc base64.hh zoneparser-tng.cc zoneparser-tng.hh rec_channel.cc rec_channel.hh \
 rec_channel_rec.cc selectmplexer.cc epollmplexer.cc sillyrecords.cc htimer.cc htimer.hh \
 aes/dns_random.cc aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c \
-lua-pdns-recursor.cc lua-pdns-recursor.hh randomhelper.cc  \
+lua-pdns.cc lua-pdns.hh lua-recursor.cc lua-recursor.hh randomhelper.cc  \
 recpacketcache.cc recpacketcache.hh dns.cc nsecrecords.cc base32.cc cachecleaner.hh
 
 pdns_recursor_LDFLAGS= $(LUA_LIBS)
index c268b9c5b0e3c5bfecf99d5595d7b086b898b798..3018a9a2d77b0fe52127089488f6d365b8c3a8c5 100644 (file)
@@ -133,6 +133,8 @@ void declareArguments()
 
   ::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("lua-prequery-script", "Lua script with prequery handler")="";
 }
 
 void declareStats(void)
index 45e275de1f83f7d76714a0d13648adabd5580985..0e62e98ba9f08ba0bf259fcb6038b0676d1f4767 100755 (executable)
@@ -9,7 +9,7 @@ rcpgenerator.hh lock.hh dnswriter.hh  dnsrecords.hh dnsparser.hh utility.hh \
 recursor_cache.hh rec_channel.hh qtype.hh misc.hh dns.hh syncres.hh \
 sstuff.hh mtasker.hh mtasker.cc lwres.hh logger.hh ahuexception.hh \
 mplexer.hh win32_mtasker.hh win32_utility.cc ntservice.hh singleton.hh \
-recursorservice.hh dns_random.hh lua-pdns-recursor.hh namespaces.hh \
+recursorservice.hh dns_random.hh lua-pdns.hh lua-recursor.hh namespaces.hh \
 recpacketcache.hh base32.hh cachecleaner.hh"
 
 CFILES="syncres.cc  misc.cc unix_utility.cc qtype.cc \
@@ -18,7 +18,7 @@ recursor_cache.cc  dnsparser.cc dnswriter.cc  dnsrecords.cc  rcpgenerator.cc  \
 base64.cc  zoneparser-tng.cc  rec_channel.cc rec_channel_rec.cc rec_control.cc \
 selectmplexer.cc epollmplexer.cc kqueuemplexer.cc portsmplexer.cc pdns_hw.cc \
 win32_mtasker.cc win32_rec_channel.cc win32_logger.cc ntservice.cc \
-recursorservice.cc sillyrecords.cc lua-pdns-recursor.cc randomhelper.cc \
+recursorservice.cc sillyrecords.cc lua-pdns.cc lua-recursor.cc randomhelper.cc \
 devpollmplexer.cc recpacketcache.cc dns.cc reczones.cc base32.cc nsecrecords.cc \
 dnslabeltext.cc"
 
diff --git a/pdns/lua-auth.cc b/pdns/lua-auth.cc
new file mode 100644 (file)
index 0000000..3cd9032
--- /dev/null
@@ -0,0 +1,227 @@
+#include "lua-auth.hh"
+
+#if !defined(PDNS_ENABLE_LUA)
+
+AuthLua::AuthLua(const std::string &fname)
+  : PowerDNSLua(fname)
+{
+  // empty
+}
+
+bool AuthLua::prequery(DNSPacket *p)
+{
+  return false;
+}
+
+bool AuthLua::axfrfilter(const ComboAddress& remote, const string& zone, const DNSResourceRecord& in, vector<DNSResourceRecord>& out)
+{
+  return false;
+}
+
+#else
+
+
+extern "C" {
+#undef L
+/* Include the Lua API header files. */
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+}
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string>
+#include <vector>
+#include <stdexcept>
+#include <boost/foreach.hpp>
+#include "logger.hh"
+#include "namespaces.hh"
+
+AuthLua::AuthLua(const std::string &fname)
+  : PowerDNSLua(fname)
+{
+  registerLuaDNSPacket();
+}
+
+bool AuthLua::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;
+}
+
+struct LuaDNSPacket
+{
+  DNSPacket *d_p;
+};
+
+static DNSPacket* ldp_checkDNSPacket(lua_State *L) {
+  void *ud = luaL_checkudata(L, 1, "LuaDNSPacket");
+  luaL_argcheck(L, ud != NULL, 1, "`LuaDNSPacket' expected");
+  return ((LuaDNSPacket *)ud)->d_p;
+}
+
+static int ldp_setRcode(lua_State *L) {
+  DNSPacket *p=ldp_checkDNSPacket(L);
+  int rcode = luaL_checkint(L, 2);
+  p->setRcode(rcode);
+  return 0;
+}
+
+static int ldp_getQuestion(lua_State *L) {
+  DNSPacket *p=ldp_checkDNSPacket(L);
+  lua_pushstring(L, p->qdomain.c_str());
+  lua_pushnumber(L, p->qtype.getCode());
+  return 2;
+}
+
+static int ldp_addRecords(lua_State *L) {
+  DNSPacket *p=ldp_checkDNSPacket(L);
+  vector<DNSResourceRecord> rrs;
+  popResourceRecordsTable(L, "BOGUS", rrs);
+  BOOST_FOREACH(DNSResourceRecord rr, rrs) {
+    p->addRecord(rr);
+  }
+  return 0;
+}
+
+static const struct luaL_reg ldp_methods [] = {
+      {"setRcode", ldp_setRcode},
+      {"getQuestion", ldp_getQuestion},
+      {"addRecords", ldp_addRecords},
+      {NULL, NULL}
+    };
+
+void AuthLua::registerLuaDNSPacket(void) {
+
+  luaL_newmetatable(d_lua, "LuaDNSPacket");
+
+  lua_pushstring(d_lua, "__index");
+  lua_pushvalue(d_lua, -2);  /* pushes the metatable */
+  lua_settable(d_lua, -3);  /* metatable.__index = metatable */
+
+  luaL_openlib(d_lua, NULL, ldp_methods, 0);
+
+  lua_pop(d_lua, 1);
+}
+
+DNSPacket* AuthLua::prequery(DNSPacket *p)
+{
+  lua_getglobal(d_lua,"prequery");
+  if(!lua_isfunction(d_lua, -1)) {
+    cerr<<"No such function 'prequery'\n";
+    lua_pop(d_lua, 1);
+    return 0;
+  }
+  
+  DNSPacket *r=0;
+  // allocate a fresh packet and prefill the question
+  r=p->replyPacket();
+
+  // wrap it
+  LuaDNSPacket* lua_dp = (LuaDNSPacket *)lua_newuserdata(d_lua, sizeof(LuaDNSPacket));
+  lua_dp->d_p=r;
+  
+  // make it of the right type
+  luaL_getmetatable(d_lua, "LuaDNSPacket");
+  lua_setmetatable(d_lua, -2);
+
+  if(lua_pcall(d_lua,  1, 1, 0)) { // error 
+    string error=string("lua error in prequery: ")+lua_tostring(d_lua, -1);
+    theL()<<Logger::Error<<error<<endl;
+
+    lua_pop(d_lua, 1);
+    throw runtime_error(error);
+    return 0;
+  }
+  bool res=lua_toboolean(d_lua, 1);
+  lua_pop(d_lua, 1);
+  if(res) {
+    // prequery created our response, use it
+    theL()<<Logger::Info<<"overriding query from lua prequery result"<<endl;
+    return r;
+  }
+  else
+  {
+    // prequery wanted nothing to do with this question
+    delete r;
+    return 0;
+  }
+}
+
+
+#endif
\ No newline at end of file
diff --git a/pdns/lua-auth.hh b/pdns/lua-auth.hh
new file mode 100644 (file)
index 0000000..35a0e90
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef PDNS_LUA_AUTH_HH
+#define PDNS_LUA_AUTH_HH
+#include "dns.hh"
+#include "iputils.hh"
+#include "dnspacket.hh"
+#include "lua-pdns.hh"
+
+class AuthLua : public PowerDNSLua
+{
+public:
+  explicit AuthLua(const std::string& fname);
+  // ~AuthLua();
+  bool axfrfilter(const ComboAddress& remote, const string& zone, const DNSResourceRecord& in, vector<DNSResourceRecord>& out);
+  DNSPacket* prequery(DNSPacket *p);
+
+private:
+  void registerLuaDNSPacket(void);
+};
+
+#endif
diff --git a/pdns/lua-pdns-recursor.cc b/pdns/lua-pdns-recursor.cc
deleted file mode 100644 (file)
index 18423b5..0000000
+++ /dev/null
@@ -1,480 +0,0 @@
-#include "lua-pdns-recursor.hh"
-// #include "syncres.hh"
-#include <boost/foreach.hpp>
-
-// to avoid including all of syncres.hh
-int directResolve(const std::string& qname, const QType& qtype, int qclass, vector<DNSResourceRecord>& ret);
-
-#if !defined(PDNS_ENABLE_LUA)
-
-// stub implementation
-
-PowerDNSLua::PowerDNSLua(const std::string& fname)
-{
-  throw runtime_error("Lua support disabled");
-}
-
-bool PowerDNSLua::nxdomain(const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res, bool* variable)
-{
-  return false;
-}
-
-bool PowerDNSLua::nodata(const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res, bool* variable)
-{
-  return false;
-}
-
-bool PowerDNSLua::postresolve(const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res, bool* variable)
-{
-  return false;
-}
-
-
-bool PowerDNSLua::preresolve(const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res, bool* variable)
-{
-  return false;
-}
-
-bool PowerDNSLua::axfrfilter(const ComboAddress& remote, const string& zone, const DNSResourceRecord& in, vector<DNSResourceRecord>& out)
-{
-  return false;
-}
-
-
-PowerDNSLua::~PowerDNSLua()
-{
-
-}
-
-#else
-
-extern "C" {
-#undef L
-/* Include the Lua API header files. */
-#include <lua.h>
-#include <lauxlib.h>
-#include <lualib.h>
-}
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string>
-#include <vector>
-#include <stdexcept>
-#include "logger.hh"
-#include "namespaces.hh"
-
-bool netmaskMatchTable(lua_State* lua, const std::string& ip)
-{
-  lua_pushnil(lua);  /* first key */
-  while (lua_next(lua, 2) != 0) {
-    string netmask=lua_tostring(lua, -1);
-    Netmask nm(netmask);
-    ComboAddress ca(ip);
-    lua_pop(lua, 1);
-    
-    if(nm.match(ip)) 
-      return true;
-  }
-  return false;
-}
-
-
-
-void pushResourceRecordsTable(lua_State* lua, const vector<DNSResourceRecord>& records)
-{  
-  // make a table of tables
-  lua_newtable(lua);
-  
-  int pos=0;
-  BOOST_FOREACH(const DNSResourceRecord& rr, records)
-  {
-    // row number, used by 'lua_settable' below
-    lua_pushnumber(lua, ++pos);
-    // "row" table
-    lua_newtable(lua);
-    
-    lua_pushstring(lua, rr.qname.c_str());
-    lua_setfield(lua, -2, "qname");  // pushes value at the top of the stack to the table immediately below that (-1 = top, -2 is below)
-    
-    lua_pushstring(lua, rr.content.c_str());
-    lua_setfield(lua, -2, "content");
-    
-    lua_pushnumber(lua, rr.qtype.getCode());
-    lua_setfield(lua, -2, "qtype");
-    
-    lua_pushnumber(lua, rr.ttl);
-    lua_setfield(lua, -2, "ttl");
-    
-    lua_pushnumber(lua, rr.d_place);
-    lua_setfield(lua, -2, "place");
-    
-    lua_settable(lua, -3); // pushes the table we just built into the master table at position pushed above
-  }
-}
-
-extern "C" {
-
-int netmaskMatchLua(lua_State *lua)
-{
-  bool result=false;
-  if(lua_gettop(lua) >= 2) {
-    string ip=lua_tostring(lua, 1);
-    if(lua_istable(lua, 2)) {
-      result = netmaskMatchTable(lua, ip);
-    }
-    else {
-      for(int n=2 ; n <= lua_gettop(lua); ++n) { 
-        string netmask=lua_tostring(lua, n);
-        Netmask nm(netmask);
-        ComboAddress ca(ip);
-        
-        result = nm.match(ip);
-        if(result)
-          break;
-      }
-    }
-  }
-  
-  lua_pushboolean(lua, result);
-  return 1;
-}
-
-int getLocalAddressLua(lua_State* lua)
-{
-  lua_getfield(lua, LUA_REGISTRYINDEX, "__PowerDNSLua"); 
-  PowerDNSLua* pl = (PowerDNSLua*)lua_touserdata(lua, -1);
-  
-  lua_pushstring(lua, pl->getLocal().toString().c_str());
-  return 1;
-}
-
-// called by lua to indicate that this answer is 'variable' and should not be cached
-int setVariableLua(lua_State* lua)
-{
-  lua_getfield(lua, LUA_REGISTRYINDEX, "__PowerDNSLua"); 
-  PowerDNSLua* pl = (PowerDNSLua*)lua_touserdata(lua, -1);
-  pl->setVariable();
-  return 0;
-}
-
-int logLua(lua_State *lua)
-{
-  if(lua_gettop(lua) >= 1) {
-    string message=lua_tostring(lua, 1);
-    theL()<<Logger::Error<<"From Lua script: "<<message<<endl;
-  }
-  return 0;
-}
-}
-
-int getFakeAAAARecords(const std::string& qname, const std::string& prefix, vector<DNSResourceRecord>& ret)
-{
-  int rcode=directResolve(qname, QType(QType::A), 1, ret);
-  
-  ComboAddress prefixAddress(prefix);
-
-  BOOST_FOREACH(DNSResourceRecord& rr, ret)
-  {    
-    if(rr.qtype.getCode() == QType::A && rr.d_place==DNSResourceRecord::ANSWER) {
-      ComboAddress ipv4(rr.content);
-      uint32_t tmp;
-      memcpy((void*)&tmp, &ipv4.sin4.sin_addr.s_addr, 4);
-      // tmp=htonl(tmp);
-      memcpy(((char*)&prefixAddress.sin6.sin6_addr.s6_addr)+12, &tmp, 4);
-      rr.content = prefixAddress.toString();
-      rr.qtype = QType(QType::AAAA);
-    }
-  }
-  return rcode;
-}
-
-
-
-PowerDNSLua::PowerDNSLua(const std::string& fname)
-{
-  d_lua = lua_open();
-
-#ifndef LUA_VERSION_NUM
-  luaopen_base(d_lua);
-  luaopen_string(d_lua);
-
-  if(lua_dofile(d_lua,  fname.c_str())) 
-#else
-  luaL_openlibs(d_lua);
-  if(luaL_dofile(d_lua,  fname.c_str())) 
-#endif
-    throw runtime_error(string("Error loading Lua file '")+fname+"': "+ string(lua_isstring(d_lua, -1) ? lua_tostring(d_lua, -1) : "unknown error"));
-
-  lua_settop(d_lua, 0);
-  
-  lua_pushcfunction(d_lua, netmaskMatchLua);
-  lua_setglobal(d_lua, "matchnetmask");
-
-  lua_pushcfunction(d_lua, logLua);
-  lua_setglobal(d_lua, "pdnslog");
-
-  lua_pushcfunction(d_lua, setVariableLua);
-  lua_setglobal(d_lua, "setvariable");
-
-  lua_pushcfunction(d_lua, getLocalAddressLua);
-  lua_setglobal(d_lua, "getlocaladdress");
-
-  lua_newtable(d_lua);
-
-  for(vector<QType::namenum>::const_iterator iter = QType::names.begin(); iter != QType::names.end(); ++iter) {
-    lua_pushnumber(d_lua, iter->second);
-    lua_setfield(d_lua, -2, iter->first.c_str());
-  }
-  lua_pushnumber(d_lua, 3);
-  lua_setfield(d_lua, -2, "NXDOMAIN");
-  lua_setglobal(d_lua, "pdns");
-  
-  lua_pushlightuserdata(d_lua, (void*)this); 
-  lua_setfield(d_lua, LUA_REGISTRYINDEX, "__PowerDNSLua");
-}
-
-bool PowerDNSLua::nxdomain(const ComboAddress& remote, const ComboAddress& local,const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res, bool* variable)
-{
-  return passthrough("nxdomain", remote, local, query, qtype, ret, res, variable);
-}
-
-bool PowerDNSLua::preresolve(const ComboAddress& remote, const ComboAddress& local,const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res, bool* variable)
-{
-  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::nodata(const ComboAddress& remote, const ComboAddress& local,const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res, bool* variable)
-{
-  return passthrough("nodata", remote, local, query, qtype, ret, res, variable);
-}
-
-bool PowerDNSLua::postresolve(const ComboAddress& remote, const ComboAddress& local,const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res, bool* variable)
-{
-  return passthrough("postresolve", remote, local, query, qtype, ret, res, variable);
-}
-
-bool PowerDNSLua::getFromTable(const std::string& key, std::string& value)
-{
-  lua_pushstring(d_lua, key.c_str()); // 4 is now '1'
-  lua_gettable(d_lua, -2);  // replace by the first entry of our table we hope
-
-  bool ret=false;
-  if(!lua_isnil(d_lua, -1)) {
-    value = lua_tostring(d_lua, -1);
-    ret=true;
-  }
-  lua_pop(d_lua, 1);
-  return ret;
-}
-
-
-bool PowerDNSLua::getFromTable(const std::string& key, uint32_t& value)
-{
-  lua_pushstring(d_lua, key.c_str()); // 4 is now '1'
-  lua_gettable(d_lua, -2);  // replace by the first entry of our table we hope
-
-  bool ret=false;
-  if(!lua_isnil(d_lua, -1)) {
-    value = (uint32_t)lua_tonumber(d_lua, -1);
-    ret=true;
-  }
-  lua_pop(d_lua, 1);
-  return ret;
-}
-
-bool PowerDNSLua::passthrough(const string& func, const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, 
-  int& res, bool* variable)
-{
-  d_variable = false;
-  lua_getglobal(d_lua,  func.c_str());
-  if(!lua_isfunction(d_lua, -1)) {
-    //  cerr<<"No such function '"<<func<<"'\n";
-    lua_pop(d_lua, 1);
-    return false;
-  }
-  
-  d_local = local; 
-  /* the first argument */
-  lua_pushstring(d_lua,  remote.toString().c_str() );
-  lua_pushstring(d_lua,  query.c_str() );
-  lua_pushnumber(d_lua,  qtype.getCode() );
-
-  int extraParameter = 0;
-  if(!strcmp(func.c_str(),"nodata")) {
-    pushResourceRecordsTable(d_lua, ret);
-    extraParameter++;
-  }
-  else if(!strcmp(func.c_str(),"postresolve")) {
-    pushResourceRecordsTable(d_lua, ret);
-    lua_pushnumber(d_lua, res);
-    extraParameter+=2;
-  }
-
-  if(lua_pcall(d_lua,  3 + extraParameter, 3, 0)) { 
-    string error=string("lua error in '"+func+"' while processing query for '"+query+"|"+qtype.getName()+": ")+lua_tostring(d_lua, -1);
-    lua_pop(d_lua, 1);
-    throw runtime_error(error);
-    return false;
-  }
-  
-  *variable |= d_variable;
-  
-  
-  if(!lua_isnumber(d_lua, 1)) {
-    string tocall = lua_tostring(d_lua,1);
-    string luaqname = lua_tostring(d_lua,2);
-    string luaprefix = lua_tostring(d_lua, 3);
-    lua_pop(d_lua, 3);
-    // cerr<<"should call '"<<tocall<<"' to finish off"<<endl;
-    ret.clear();
-    res=getFakeAAAARecords(luaqname, luaprefix, ret);
-    return true;
-    // returned a followup 
-  }
-  
-  int newres = (int)lua_tonumber(d_lua, 1); // new rcode
-  if(newres < 0) {
-    //    cerr << "handler did not handle"<<endl;
-    lua_pop(d_lua, 3);
-    return false;
-  }
-  res=newres;
-
-  /* get the result */
-  DNSResourceRecord rr;
-  rr.qname = query;
-  rr.d_place = DNSResourceRecord::ANSWER;
-  rr.ttl = 3600;
-
-  ret.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<<"Got back "<<tableLen<< " answers from Lua"<<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 = query;
-
-    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";
-    ret.push_back(rr);
-  }
-
-  lua_pop(d_lua, 3);
-
-  return true;
-}
-
-PowerDNSLua::~PowerDNSLua()
-{
-  lua_close(d_lua);
-}
-#endif
diff --git a/pdns/lua-pdns.cc b/pdns/lua-pdns.cc
new file mode 100644 (file)
index 0000000..6f77b02
--- /dev/null
@@ -0,0 +1,272 @@
+#include "lua-pdns.hh"
+// #include "syncres.hh"
+#include <boost/foreach.hpp>
+
+#if !defined(PDNS_ENABLE_LUA)
+
+// stub implementation
+
+PowerDNSLua::PowerDNSLua(const std::string& fname)
+{
+  throw runtime_error("Lua support disabled");
+}
+
+
+PowerDNSLua::~PowerDNSLua()
+{
+
+}
+
+#else
+
+extern "C" {
+#undef L
+/* Include the Lua API header files. */
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+}
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string>
+#include <vector>
+#include <stdexcept>
+#include "logger.hh"
+#include "namespaces.hh"
+
+bool netmaskMatchTable(lua_State* lua, const std::string& ip)
+{
+  lua_pushnil(lua);  /* first key */
+  while (lua_next(lua, 2) != 0) {
+    string netmask=lua_tostring(lua, -1);
+    Netmask nm(netmask);
+    ComboAddress ca(ip);
+    lua_pop(lua, 1);
+    
+    if(nm.match(ip)) 
+      return true;
+  }
+  return false;
+}
+
+static bool getFromTable(lua_State *lua, const std::string &key, std::string& value)
+{
+  lua_pushstring(lua, key.c_str()); // 4 is now '1'
+  lua_gettable(lua, -2);  // replace by the first entry of our table we hope
+
+  bool ret=false;
+  if(!lua_isnil(lua, -1)) {
+    value = lua_tostring(lua, -1);
+    ret=true;
+  }
+  lua_pop(lua, 1);
+  return ret;
+}
+
+static bool getFromTable(lua_State *lua, const std::string &key, uint32_t& value)
+{
+  lua_pushstring(lua, key.c_str()); // 4 is now '1'
+  lua_gettable(lua, -2);  // replace by the first entry of our table we hope
+
+  bool ret=false;
+  if(!lua_isnil(lua, -1)) {
+    value = (uint32_t)lua_tonumber(lua, -1);
+    ret=true;
+  }
+  lua_pop(lua, 1);
+  return ret;
+}
+
+void pushResourceRecordsTable(lua_State* lua, const vector<DNSResourceRecord>& records)
+{  
+  // make a table of tables
+  lua_newtable(lua);
+  
+  int pos=0;
+  BOOST_FOREACH(const DNSResourceRecord& rr, records)
+  {
+    // row number, used by 'lua_settable' below
+    lua_pushnumber(lua, ++pos);
+    // "row" table
+    lua_newtable(lua);
+    
+    lua_pushstring(lua, rr.qname.c_str());
+    lua_setfield(lua, -2, "qname");  // pushes value at the top of the stack to the table immediately below that (-1 = top, -2 is below)
+    
+    lua_pushstring(lua, rr.content.c_str());
+    lua_setfield(lua, -2, "content");
+    
+    lua_pushnumber(lua, rr.qtype.getCode());
+    lua_setfield(lua, -2, "qtype");
+    
+    lua_pushnumber(lua, rr.ttl);
+    lua_setfield(lua, -2, "ttl");
+    
+    lua_pushnumber(lua, rr.d_place);
+    lua_setfield(lua, -2, "place");
+    
+    lua_settable(lua, -3); // pushes the table we just built into the master table at position pushed above
+  }
+}
+
+void popResourceRecordsTable(lua_State *lua, const string &query, vector<DNSResourceRecord>& ret)
+{
+  /* get the result */
+  DNSResourceRecord rr;
+  rr.qname = query;
+  rr.d_place = DNSResourceRecord::ANSWER;
+  rr.ttl = 3600;
+
+  cerr<<"Lua stacksize "<<lua_gettop(lua)<<endl;
+#ifndef LUA_VERSION_NUM
+  int tableLen = luaL_getn(lua, 2);
+#else
+  int tableLen = lua_objlen(lua, 2);
+#endif
+  cerr<<"Got back "<<tableLen<< " answers from Lua"<<endl;
+
+  for(int n=1; n < tableLen + 1; ++n) {
+    lua_pushnumber(lua, n);
+    lua_gettable(lua, 2);
+
+    uint32_t tmpnum=0;
+    if(!getFromTable(lua, "qtype", tmpnum)) 
+      rr.qtype=QType::A;
+    else
+      rr.qtype=tmpnum;
+
+    getFromTable(lua, "content", rr.content);
+    if(!getFromTable(lua, "ttl", rr.ttl))
+      rr.ttl=3600;
+
+    if(!getFromTable(lua, "qname", rr.qname))
+      rr.qname = query;
+
+    if(!getFromTable(lua, "place", tmpnum))
+      rr.d_place = DNSResourceRecord::ANSWER;
+    else
+      rr.d_place = (DNSResourceRecord::Place) tmpnum;
+
+    /* removes 'value'; keeps 'key' for next iteration */
+    lua_pop(lua, 1); // table
+
+    //    cerr<<"Adding content '"<<rr.content<<"' with place "<<(int)rr.d_place<<" \n";
+    ret.push_back(rr);
+  }
+}
+
+extern "C" {
+
+int netmaskMatchLua(lua_State *lua)
+{
+  bool result=false;
+  if(lua_gettop(lua) >= 2) {
+    string ip=lua_tostring(lua, 1);
+    if(lua_istable(lua, 2)) {
+      result = netmaskMatchTable(lua, ip);
+    }
+    else {
+      for(int n=2 ; n <= lua_gettop(lua); ++n) { 
+        string netmask=lua_tostring(lua, n);
+        Netmask nm(netmask);
+        ComboAddress ca(ip);
+        
+        result = nm.match(ip);
+        if(result)
+          break;
+      }
+    }
+  }
+  
+  lua_pushboolean(lua, result);
+  return 1;
+}
+
+int getLocalAddressLua(lua_State* lua)
+{
+  lua_getfield(lua, LUA_REGISTRYINDEX, "__PowerDNSLua"); 
+  PowerDNSLua* pl = (PowerDNSLua*)lua_touserdata(lua, -1);
+  
+  lua_pushstring(lua, pl->getLocal().toString().c_str());
+  return 1;
+}
+
+// called by lua to indicate that this answer is 'variable' and should not be cached
+int setVariableLua(lua_State* lua)
+{
+  lua_getfield(lua, LUA_REGISTRYINDEX, "__PowerDNSLua"); 
+  PowerDNSLua* pl = (PowerDNSLua*)lua_touserdata(lua, -1);
+  pl->setVariable();
+  return 0;
+}
+
+int logLua(lua_State *lua)
+{
+  if(lua_gettop(lua) >= 1) {
+    string message=lua_tostring(lua, 1);
+    theL()<<Logger::Error<<"From Lua script: "<<message<<endl;
+  }
+  return 0;
+}
+}
+
+PowerDNSLua::PowerDNSLua(const std::string& fname)
+{
+  d_lua = lua_open();
+
+#ifndef LUA_VERSION_NUM
+  luaopen_base(d_lua);
+  luaopen_string(d_lua);
+
+  if(lua_dofile(d_lua,  fname.c_str())) 
+#else
+  luaL_openlibs(d_lua);
+  if(luaL_dofile(d_lua,  fname.c_str())) 
+#endif
+    throw runtime_error(string("Error loading Lua file '")+fname+"': "+ string(lua_isstring(d_lua, -1) ? lua_tostring(d_lua, -1) : "unknown error"));
+
+  lua_settop(d_lua, 0);
+  
+  lua_pushcfunction(d_lua, netmaskMatchLua);
+  lua_setglobal(d_lua, "matchnetmask");
+
+  lua_pushcfunction(d_lua, logLua);
+  lua_setglobal(d_lua, "pdnslog");
+
+  lua_pushcfunction(d_lua, setVariableLua);
+  lua_setglobal(d_lua, "setvariable");
+
+  lua_pushcfunction(d_lua, getLocalAddressLua);
+  lua_setglobal(d_lua, "getlocaladdress");
+
+  lua_newtable(d_lua);
+
+  for(vector<QType::namenum>::const_iterator iter = QType::names.begin(); iter != QType::names.end(); ++iter) {
+    lua_pushnumber(d_lua, iter->second);
+    lua_setfield(d_lua, -2, iter->first.c_str());
+  }
+  lua_pushnumber(d_lua, 3);
+  lua_setfield(d_lua, -2, "NXDOMAIN");
+  lua_setglobal(d_lua, "pdns");
+  
+  lua_pushlightuserdata(d_lua, (void*)this); 
+  lua_setfield(d_lua, LUA_REGISTRYINDEX, "__PowerDNSLua");
+}
+
+bool PowerDNSLua::getFromTable(const std::string& key, std::string& value)
+{
+  return ::getFromTable(d_lua, key, value);
+}
+
+bool PowerDNSLua::getFromTable(const std::string& key, uint32_t& value)
+{
+  return ::getFromTable(d_lua, key, value);
+}
+
+
+PowerDNSLua::~PowerDNSLua()
+{
+  lua_close(d_lua);
+}
+#endif
diff --git a/pdns/lua-pdns.hh b/pdns/lua-pdns.hh
new file mode 100644 (file)
index 0000000..ddecdff
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef PDNS_LUA_PDNS_HH
+#define PDNS_LUA_PDNS_HH
+#include "dns.hh"
+#include "iputils.hh"
+
+struct lua_State;
+
+class PowerDNSLua
+{
+public:
+  explicit PowerDNSLua(const std::string& fname);
+  ~PowerDNSLua();
+  void reload();
+  ComboAddress getLocal()
+  {
+    return d_local;
+  }
+
+  void setVariable()
+  {
+    d_variable=true;
+  }
+
+protected: // FIXME?
+  lua_State* d_lua;
+  bool passthrough(const string& func, const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res, bool* variable);
+  bool getFromTable(const std::string& key, std::string& value);
+  bool getFromTable(const std::string& key, uint32_t& value);
+  bool d_failed;
+  bool d_variable;  
+  ComboAddress d_local;
+};
+
+void pushResourceRecordsTable(lua_State* lua, const vector<DNSResourceRecord>& records);
+void popResourceRecordsTable(lua_State *lua, const string &query, vector<DNSResourceRecord>& ret);
+
+#endif
diff --git a/pdns/lua-recursor.cc b/pdns/lua-recursor.cc
new file mode 100644 (file)
index 0000000..70dad60
--- /dev/null
@@ -0,0 +1,173 @@
+#include "lua-recursor.hh"
+
+// to avoid including all of syncres.hh
+int directResolve(const std::string& qname, const QType& qtype, int qclass, vector<DNSResourceRecord>& ret);
+
+#if !defined(PDNS_ENABLE_LUA)
+
+RecursorLua::RecursorLua(const std::string &fname)
+  : PowerDNSLua(fname)
+{
+  // empty
+}
+
+bool RecursorLua::nxdomain(const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res, bool* variable)
+{
+  return false;
+}
+
+bool RecursorLua::nodata(const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res, bool* variable)
+{
+  return false;
+}
+
+bool RecursorLua::postresolve(const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res, bool* variable)
+{
+  return false;
+}
+
+
+bool RecursorLua::preresolve(const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res, bool* variable)
+{
+  return false;
+}
+
+
+#else
+
+extern "C" {
+#undef L
+/* Include the Lua API header files. */
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+}
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string>
+#include <vector>
+#include <stdexcept>
+#include <boost/foreach.hpp>
+#include "logger.hh"
+#include "namespaces.hh"
+
+RecursorLua::RecursorLua(const std::string &fname)
+  : PowerDNSLua(fname)
+{
+  // empty
+}
+
+int getFakeAAAARecords(const std::string& qname, const std::string& prefix, vector<DNSResourceRecord>& ret)
+{
+  int rcode=directResolve(qname, QType(QType::A), 1, ret);
+  
+  ComboAddress prefixAddress(prefix);
+
+  BOOST_FOREACH(DNSResourceRecord& rr, ret)
+  {    
+    if(rr.qtype.getCode() == QType::A && rr.d_place==DNSResourceRecord::ANSWER) {
+      ComboAddress ipv4(rr.content);
+      uint32_t tmp;
+      memcpy((void*)&tmp, &ipv4.sin4.sin_addr.s_addr, 4);
+      // tmp=htonl(tmp);
+      memcpy(((char*)&prefixAddress.sin6.sin6_addr.s6_addr)+12, &tmp, 4);
+      rr.content = prefixAddress.toString();
+      rr.qtype = QType(QType::AAAA);
+    }
+  }
+  return rcode;
+}
+
+bool RecursorLua::nxdomain(const ComboAddress& remote, const ComboAddress& local,const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res, bool* variable)
+{
+  return passthrough("nxdomain", remote, local, query, qtype, ret, res, variable);
+}
+
+bool RecursorLua::preresolve(const ComboAddress& remote, const ComboAddress& local,const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res, bool* variable)
+{
+  return passthrough("preresolve", remote, local, query, qtype, ret, res, variable);
+}
+
+bool RecursorLua::nodata(const ComboAddress& remote, const ComboAddress& local,const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res, bool* variable)
+{
+  return passthrough("nodata", remote, local, query, qtype, ret, res, variable);
+}
+
+bool RecursorLua::postresolve(const ComboAddress& remote, const ComboAddress& local,const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res, bool* variable)
+{
+  return passthrough("postresolve", remote, local, query, qtype, ret, res, variable);
+}
+
+
+bool RecursorLua::passthrough(const string& func, const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, 
+  int& res, bool* variable)
+{
+  d_variable = false;
+  lua_getglobal(d_lua,  func.c_str());
+  if(!lua_isfunction(d_lua, -1)) {
+    //  cerr<<"No such function '"<<func<<"'\n";
+    lua_pop(d_lua, 1);
+    return false;
+  }
+  
+  d_local = local; 
+  /* the first argument */
+  lua_pushstring(d_lua,  remote.toString().c_str() );
+  lua_pushstring(d_lua,  query.c_str() );
+  lua_pushnumber(d_lua,  qtype.getCode() );
+
+  int extraParameter = 0;
+  if(!strcmp(func.c_str(),"nodata")) {
+    pushResourceRecordsTable(d_lua, ret);
+    extraParameter++;
+  }
+  else if(!strcmp(func.c_str(),"postresolve")) {
+    pushResourceRecordsTable(d_lua, ret);
+    lua_pushnumber(d_lua, res);
+    extraParameter+=2;
+  }
+
+  if(lua_pcall(d_lua,  3 + extraParameter, 3, 0)) { 
+    string error=string("lua error in '"+func+"' while processing query for '"+query+"|"+qtype.getName()+": ")+lua_tostring(d_lua, -1);
+    lua_pop(d_lua, 1);
+    throw runtime_error(error);
+    return false;
+  }
+  
+  *variable |= d_variable;
+  
+  
+  if(!lua_isnumber(d_lua, 1)) {
+    string tocall = lua_tostring(d_lua,1);
+    string luaqname = lua_tostring(d_lua,2);
+    string luaprefix = lua_tostring(d_lua, 3);
+    lua_pop(d_lua, 3);
+    // cerr<<"should call '"<<tocall<<"' to finish off"<<endl;
+    ret.clear();
+    res=getFakeAAAARecords(luaqname, luaprefix, ret);
+    return true;
+    // returned a followup 
+  }
+  
+  int newres = (int)lua_tonumber(d_lua, 1); // new rcode
+  if(newres < 0) {
+    //    cerr << "handler did not handle"<<endl;
+    lua_pop(d_lua, 3);
+    return false;
+  }
+  res=newres;
+
+  ret.clear();
+
+  /*           1       2   3   4   */
+  /* stack:  boolean table key row */
+
+  popResourceRecordsTable(d_lua, query, ret);
+
+  lua_pop(d_lua, 3);
+
+  return true;
+}
+
+#endif
\ No newline at end of file
similarity index 60%
rename from pdns/lua-pdns-recursor.hh
rename to pdns/lua-recursor.hh
index 050dfe82399b03502a4ab3367fe5b03432c7f4c2..62eaead2aa75c62ed848594c7b0d5a3a1829968a 100644 (file)
@@ -1,39 +1,21 @@
-#ifndef PDNS_LUA_PDNS_RECURSOR_HH
-#define PDNS_LUA_PDNS_RECURSOR_HH
+#ifndef PDNS_LUA_RECURSOR_HH
+#define PDNS_LUA_RECURSOR_HH
 #include "dns.hh"
 #include "iputils.hh"
+#include "lua-pdns.hh"
 
-struct lua_State;
-
-class PowerDNSLua
+class RecursorLua : public PowerDNSLua
 {
 public:
-  explicit PowerDNSLua(const std::string& fname);
-  ~PowerDNSLua();
-  void reload();
+  explicit RecursorLua(const std::string& fname);
+  // ~RecursorLua();
   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);
   bool nodata(const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector<DNSResourceRecord>& res, int& ret, bool* variable);
   bool postresolve(const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector<DNSResourceRecord>& res, int& ret, bool* variable);
-  ComboAddress getLocal()
-  {
-    return d_local;
-  }
-
-  void setVariable()
-  {
-    d_variable=true;
-  }
 
 private:
-  lua_State* d_lua;
   bool passthrough(const string& func, const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res, bool* variable);
-  bool getFromTable(const std::string& key, std::string& value);
-  bool getFromTable(const std::string& key, uint32_t& value);
-  bool d_failed;
-  bool d_variable;  
-  ComboAddress d_local;
 };
 
 #endif
index fb3bf2ef4eab49c9d14ec114d8a123ec64a2ac36..0c51fe65f05dae8dd6929df761a856dcbe8e9dfc 100644 (file)
@@ -58,6 +58,16 @@ PacketHandler::PacketHandler():B(s_programname)
   d_doRecursion= ::arg().mustDo("recursor");
   d_logDNSDetails= ::arg().mustDo("log-dns-details");
   d_doIPv6AdditionalProcessing = ::arg().mustDo("do-ipv6-additional-processing");
+  string fname= ::arg()["lua-prequery-script"];
+  if(fname.empty())
+  {
+    d_pdl = NULL;
+  }
+  else
+  {
+    d_pdl = new AuthLua(fname);
+  }
+
 }
 
 DNSBackend *PacketHandler::getBackend()
@@ -839,8 +849,17 @@ bool validDNSName(const string &name)
 
 DNSPacket *PacketHandler::question(DNSPacket *p)
 {
+  DNSPacket *ret;
+
+  if(d_pdl)
+  {
+    ret=d_pdl->prequery(p);
+    if(ret)
+      return ret;
+  }
+
   bool shouldRecurse=false;
-  DNSPacket *ret=questionOrRecurse(p, &shouldRecurse);
+  ret=questionOrRecurse(p, &shouldRecurse);
   if(shouldRecurse) {
     DP->sendPacket(p);
   }
index c01aa8cefb0e729e8bae796ab2b8dbab4c88d48f..e62cbf6051741c07e36bb7b86371a0685be1a142 100644 (file)
@@ -29,6 +29,7 @@
 #include "dnspacket.hh"
 #include "packetcache.hh"
 #include "dnsseckeeper.hh"
+#include "lua-auth.hh"
 
 #include "namespaces.hh"
 
@@ -122,6 +123,7 @@ private:
   bool d_doCNAME;
   bool d_logDNSDetails;
   bool d_doIPv6AdditionalProcessing;
+  AuthLua* d_pdl;
 
   UeberBackend B; // every thread an own instance
   DNSSECKeeper d_dk; // same, might even share B?
index 6b5fad4c5e82bac2480335b26848e2e06831460f..cb1527ea32512c0eb25d5263c6ee8a40d89a2fa0 100644 (file)
@@ -64,7 +64,7 @@
 #include "iputils.hh"
 #include "mplexer.hh"
 #include "config.h"
-#include "lua-pdns-recursor.hh"
+#include "lua-recursor.hh"
 
 #ifndef RECURSOR
 #include "statbag.hh"
@@ -76,7 +76,7 @@ __thread unsigned int t_id;
 unsigned int g_maxTCPPerClient;
 unsigned int g_networkTimeoutMsec;
 bool g_logCommonErrors;
-__thread shared_ptr<PowerDNSLua>* t_pdl;
+__thread shared_ptr<RecursorLua>* t_pdl;
 __thread RemoteKeeper* t_remotes;
 
 RecursorControlChannel s_rcc; // only active in thread 0
@@ -521,7 +521,7 @@ void startDoResolve(void *p)
     int res;
 
     bool variableAnswer = false;
-    // if there is a PowerDNSLua active, and it 'took' the query in preResolve, we don't launch beginResolve
+    // if there is a RecursorLua active, and it 'took' the query in preResolve, we don't launch beginResolve
     if(!t_pdl->get() || !(*t_pdl)->preresolve(dc->d_remote, g_listenSocketsAddresses[dc->d_socket], dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), ret, res, &variableAnswer)) {
        res = sr.beginResolve(dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_mdp.d_qclass, ret);
 
@@ -1511,7 +1511,7 @@ string* doReloadLuaScript()
       return new string("unloaded\n");
     }
     else {
-      *t_pdl = shared_ptr<PowerDNSLua>(new PowerDNSLua(fname));
+      *t_pdl = shared_ptr<RecursorLua>(new RecursorLua(fname));
     }
   }
   catch(std::exception& e) {
@@ -1806,11 +1806,11 @@ try
   L<<Logger::Warning<<"Done priming cache with root hints"<<endl;
     
   t_RC->d_followRFC2181=::arg().mustDo("auth-can-lower-ttl");
-  t_pdl = new shared_ptr<PowerDNSLua>();
+  t_pdl = new shared_ptr<RecursorLua>();
   
   try {
     if(!::arg()["lua-dns-script"].empty()) {
-      *t_pdl = shared_ptr<PowerDNSLua>(new PowerDNSLua(::arg()["lua-dns-script"]));
+      *t_pdl = shared_ptr<RecursorLua>(new RecursorLua(::arg()["lua-dns-script"]));
       L<<Logger::Warning<<"Loaded 'lua' script from '"<<::arg()["lua-dns-script"]<<"'"<<endl;
     }
     
index 46ea6e4a6c89cfba5093057b46ab18358bf6f119..5cab16e941c520121135270ae7a8c02f1c9255e2 100644 (file)
@@ -96,4 +96,25 @@ function postresolve ( remoteip, domain, qtype, records, origrcode )
        --      print(val.content)
        end
        return origrcode, records
-end    
\ No newline at end of file
+end    
+
+function prequery ( dnspacket )
+       -- pdnslog ("prequery called for ".. tostring(dnspacket) )
+       qname, qtype = dnspacket:getQuestion()
+       pdnslog ("q: ".. qname.." "..qtype)
+       if qtype == pdns.A and qname == "www.domain.com" 
+       then
+               pdnslog ("calling dnspacket:setRcode")
+               dnspacket:setRcode(pdns.NXDOMAIN)
+               pdnslog ("called dnspacket:setRcode")
+               pdnslog ("adding records")
+               ret = {}
+               ret[1] = {qname=qname, qtype=qtype, content="1.2.3.4", place=2}
+               ret[2] = {qname=qname, qtype=pdns.TXT, content=os.date("Retrieved at %Y-%m-%d %H:%M"), ttl=ttl}
+               dnspacket:addRecords(ret)
+               pdnslog ("returning true")
+               return true
+       end
+       pdnslog ("returning false")
+       return false
+end
index e01262085a06ef6652a2096ac0b1c0124ad88951..d7111dc26b6fc787ce423544b6a432c43cb89775 100644 (file)
@@ -37,7 +37,7 @@
 #include <boost/lexical_cast.hpp>
 #include "base64.hh"
 #include "inflighter.cc"
-#include "lua-pdns-recursor.hh"
+#include "lua-auth.hh"
 #include "namespaces.hh"
 #include "common_startup.hh"
 #include <boost/scoped_ptr.hpp>
@@ -132,11 +132,11 @@ void CommunicatorClass::suck(const string &domain,const string &remote)
       }
     }
     
-    scoped_ptr<PowerDNSLua> pdl;
+    scoped_ptr<AuthLua> pdl;
     vector<string> scripts;
     if(B->getDomainMetadata(domain, "LUA-AXFR-SCRIPT", scripts) && !scripts.empty()) {
       try {
-        pdl.reset(new PowerDNSLua(scripts[0]));
+        pdl.reset(new AuthLua(scripts[0]));
         L<<Logger::Info<<"Loaded Lua script '"<<scripts[0]<<"' to edit the incoming AXFR of '"<<domain<<"'"<<endl;
       }
       catch(std::exception& e) {