]> granicus.if.org Git - pdns/commitdiff
add Lua backend, add to tar.gz, .deb and rpm
authorBert Hubert <bert.hubert@netherlabs.nl>
Sun, 5 Jun 2011 18:27:45 +0000 (18:27 +0000)
committerBert Hubert <bert.hubert@netherlabs.nl>
Sun, 5 Jun 2011 18:27:45 +0000 (18:27 +0000)
git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@2208 d19b8d6e-7fed-0310-83ef-9ca221ded41b

25 files changed:
build-scripts/rpm-build-instruction
build-scripts/tar-gz-build-instruction
configure.ac
modules/luabackend/Makefile.am [new file with mode: 0644]
modules/luabackend/OBJECTFILES [new file with mode: 0644]
modules/luabackend/OBJECTLIBS [new file with mode: 0644]
modules/luabackend/README [new file with mode: 0644]
modules/luabackend/dnssec.cc [new file with mode: 0644]
modules/luabackend/lua_functions.cc [new file with mode: 0644]
modules/luabackend/lua_functions.hh [new file with mode: 0644]
modules/luabackend/luabackend.cc [new file with mode: 0644]
modules/luabackend/luabackend.hh [new file with mode: 0644]
modules/luabackend/master.cc [new file with mode: 0644]
modules/luabackend/minimal.cc [new file with mode: 0644]
modules/luabackend/private.cc [new file with mode: 0644]
modules/luabackend/reload.cc [new file with mode: 0644]
modules/luabackend/slave.cc [new file with mode: 0644]
modules/luabackend/supermaster.cc [new file with mode: 0644]
modules/luabackend/test/dnsperf [new file with mode: 0755]
modules/luabackend/test/one [new file with mode: 0644]
modules/luabackend/test/pdns [new file with mode: 0755]
modules/luabackend/test/pdns.conf [new file with mode: 0644]
modules/luabackend/test/pdns.pid [new file with mode: 0644]
modules/luabackend/test/pdnssec [new file with mode: 0755]
modules/luabackend/test/powerdns-luabackend.lua [new file with mode: 0644]

index f3402c9553259ac76728caee4dccac1f581c27ab..631f21fbb0c75e6956c3f8d8258c6a7b37d4609c 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 #LIBS="-lkrb5 -lk5crypto -lpgport -lgssapi_krb5 -lkrb5support -lgssapi_krb5 -lcom_err -lnsl -lresolv" \
 CC="ccache gcc" CXX="ccache g++" ./configure \
-               --with-modules="mysql gmysql gpgsql gsqlite gsqlite3 pipe pdns geo" \
+               --with-modules="mysql gmysql gpgsql gsqlite gsqlite3 pipe pdns geo lua" \
        --with-dynmodules="" \
        --enable-static-binaries \
        --with-pgsql-lib=/opt/postgresql/lib --with-pgsql-includes=/opt/postgresql/include \
index 3deb39aef72b11ca8d284e706fbfc07d029e6322..e1435dc013df6a07dcbf328ecfb567fbf98fd0c0 100755 (executable)
@@ -2,6 +2,6 @@ rm -f $(find . -name "*~") &&
 ./bootstrap && 
 ./configure \
 --with-pgsql-lib=/opt/postgresql/lib --with-pgsql-includes=/opt/postgresql/include \
---with-modules="mysql mydns gmysql mongodb gpgsql xdb pipe oracle pipe pdns db2 odbc ldap gsqlite gsqlite3 geo goracle opendbx godbc" \
+--with-modules="mysql mydns gmysql mongodb lua gpgsql xdb pipe oracle pipe pdns db2 odbc ldap gsqlite gsqlite3 geo goracle opendbx godbc" \
 --with-dynmodules="" &&
 make dist 
\ No newline at end of file
index 66435d5c46260ec4e1575fff59a20f5f31a506cd..2e8e1f4c6397b2770241d8d3a73e295a954b8bf9 100644 (file)
@@ -646,6 +646,7 @@ modules/geobackend/Makefile modules/opendbxbackend/Makefile \
 modules/pipebackend/Makefile modules/oraclebackend/Makefile \
 modules/xdbbackend/Makefile modules/godbcbackend/Makefile \
 modules/odbcbackend/Makefile modules/mongodbbackend/Makefile \
-modules/gpgsqlbackend/Makefile modules/ldapbackend/Makefile 
-modules/gsqlitebackend/Makefile modules/gsqlite3backend/Makefile
-modules/goraclebackend/Makefile modules/mydnsbackend/Makefile)
+modules/gpgsqlbackend/Makefile modules/ldapbackend/Makefile \
+modules/gsqlitebackend/Makefile modules/gsqlite3backend/Makefile \
+modules/goraclebackend/Makefile modules/mydnsbackend/Makefile \
+modules/luabackend/Makefile )
diff --git a/modules/luabackend/Makefile.am b/modules/luabackend/Makefile.am
new file mode 100644 (file)
index 0000000..406b80e
--- /dev/null
@@ -0,0 +1,11 @@
+AM_CPPFLAGS=@THREADFLAGS@
+EXTRA_DIST=OBJECTFILES OBJECTLIBS 
+
+INCLUDES=-I/usr/include/lua5.1
+#INCLUDES=-I/usr/local/include/luajit-2.0 -DUSE_LUAJIT
+
+lib_LTLIBRARIES = libluabackend.la
+
+libluabackend_la_SOURCES=luabackend.cc luabackend.hh minimal.cc reload.cc lua_functions.cc master.cc private.cc slave.cc supermaster.cc dnssec.cc 
+libluabackend_la_LDFLAGS=-module -avoid-version -llua5.1
+#-lluajit-5.1
diff --git a/modules/luabackend/OBJECTFILES b/modules/luabackend/OBJECTFILES
new file mode 100644 (file)
index 0000000..3c78d71
--- /dev/null
@@ -0,0 +1 @@
+luabackend.o minimal.o reload.o lua_functions.o master.o private.o slave.o supermaster.o dnssec.o
\ No newline at end of file
diff --git a/modules/luabackend/OBJECTLIBS b/modules/luabackend/OBJECTLIBS
new file mode 100644 (file)
index 0000000..cab8575
--- /dev/null
@@ -0,0 +1 @@
+-llua5.1
\ No newline at end of file
diff --git a/modules/luabackend/README b/modules/luabackend/README
new file mode 100644 (file)
index 0000000..fdbc5ab
--- /dev/null
@@ -0,0 +1,137 @@
+====================================
+This is the luabackend for PowerDNS!
+====================================
+
+This backend is just a "glue" between PowerDNS and your own Lua application.
+
+This does mean that you can not have a working setup that can serve you
+dns-questions directly from start. What you need to do is to program your own 
+backend completly in Lua! Which database server to use etc is now up to you!
+
+What you have here is the possibility to make your own "dns-server" without the 
+knowledge of programming in c/c++.
+
+There is one thing that needs to be sad. Remember that each thread 
+PowerDNS launch of this backend is completly different so they cannot 
+share information between each other! 
+
+You will need some kind of a database that can be shared for this.
+
+All the functionsname that PowerDNS except for a backend should be the same
+in your Lua script, in lowercase. Also, the parameters should be in the same 
+order. Where there is a struture in c/c++ there is a table in the Lua backend.
+This is also true for returnvalues.
+
+
+=============
+NEW FUNCTIONS
+=============
+
+There is a couple of new functions for you to use in Lua:
+
+-----------------------------------
+logger(log_facility, "your messages")
+-----------------------------------
+
+All these log_facilities is availible:
+log_all, log_ntlog, log_alert, log_critical, log_error, log_warning, log_notice,
+log_info, log_debug, log_none
+
+
+-----------
+dnspacket()
+-----------
+
+This will give you back three parameters with
+remote_ip, remote_port and local_ip in that order.
+
+Can only be used for the functions list() and getsoa().
+
+
+------------------------
+getarg("your_parameter")
+------------------------
+
+Thisone tries to get the value of the name "lua-your_parameter" from the pdns.conf file.
+
+
+------------------------
+mustdo("your_parameter")
+------------------------
+
+This is the same as getarg() but return a boolean instead of a string.
+
+
+You also have all the different QTypes in a table called 'QTypes'.
+
+
+====================
+WHAT HAS BEEN TESTED
+====================
+
+The only functionallity of the mininal functions except zone-transfer has
+been tested. 
+
+In the included powerdns-luabackend.lua file there is a example of how
+this can be done. Note that this is more or less a static example since
+there is no possiblity for each thread to know when something has changed.
+
+However, you run 'pdns_control reload' and it should reload the hole thing 
+from scratch.
+
+
+===========================================
+WHAT YOU WILL FIND UNDER THE TEST DIRECTORY
+===========================================
+
+The script 'pdns' is used to test the server on the ip address '127.0.0.1' with
+the port 5300. You should be able to run the following test with the included 
+'powerdns-luabackend.lua' file:
+
+$dig any www.test.com @127.0.0.1 -p5300 +multiline
+; <<>> DiG 9.7.3 <<>> any www.test.com @127.0.0.1 -p5300 +multiline
+;; global options: +cmd
+;; Got answer:
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1001
+;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0
+;; WARNING: recursion requested but not available
+
+;; QUESTION SECTION:
+;www.test.com.          IN ANY
+
+;; ANSWER SECTION:
+www.test.com.           120 IN CNAME host.test.com.
+host.test.com.          120 IN A 10.11.12.13
+host.test.com.          120 IN AAAA 1:2:3:4:5:6:7:8
+
+;; Query time: 1 msec
+;; SERVER: 127.0.0.1#5300(127.0.0.1)
+;; WHEN: Thu Jun  2 22:19:56 2011
+;; MSG SIZE  rcvd: 93
+
+
+=============================
+OPTIONS IN THE CONFIGURE FILE
+=============================
+
+The default values is:
+
+lua-filename = powerdns-luabackend.lua
+
+You can also override all the default functionsnames for the luafunctions if you want.
+The prefix is lua-f_<functionname>=mynewfunction. For example:
+
+lua-f_lookup = mynewfunction 
+
+will call the function 'mynewfunction' for the lookup-routine.
+
+If you want your own configuration parameters you can have that too. 
+Just call the function getarg("my_parameter") and it will return the value
+of 'lua-my_parameter'. For boolean you use the function mustdo("my_parameter").
+
+
+
+You can send question about this backend to >dev/null first and if you don't get any 
+answer from that you can try to send them to me at fredan-pdns@fredan.org
+
+Fredrik Danerklint.
\ No newline at end of file
diff --git a/modules/luabackend/dnssec.cc b/modules/luabackend/dnssec.cc
new file mode 100644 (file)
index 0000000..df93fda
--- /dev/null
@@ -0,0 +1,614 @@
+/*
+    Copyright (C) 2011 Fredrik Danerklint
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License version 2 as published 
+    by the Free Software Foundation
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+
+#include "luabackend.hh"
+
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+
+/* 
+    virtual bool updateDNSSECOrderAndAuth(uint32_t domain_id, const std::string& zonename, const std::string& qname, bool auth) 
+    virtual bool updateDNSSECOrderAndAuthAbsolute(uint32_t domain_id, const std::string& qname, const std::string& ordername, bool auth) 
+    virtual bool getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, std::string& unhashed, std::string& before, std::string& after)
+
+    virtual bool getDomainKeys(const string& name, unsigned int kind, std::vector<KeyData>& keys)
+    virtual bool removeDomainKey(const string& name, unsigned int id)
+    virtual int addDomainKey(const string& name, const KeyData& key)
+    virtual bool activateDomainKey(const string& name, unsigned int id)
+    virtual bool deactivateDomainKey(const string& name, unsigned int id)
+
+    virtual bool getTSIGKey(const string& name, string* algorithm, string* content) { return false; }
+
+    virtual bool setDomainMetadata(const string& name, const std::string& kind, std::vector<std::string>& meta)
+    virtual bool getDomainMetadata(const string& name, const std::string& kind, std::vector<std::string>& meta)
+    virtual void alsoNotifies(const string &domain, set<string> *ips)
+
+*/
+
+bool LUABackend::updateDNSSECOrderAndAuth(uint32_t domain_id, const std::string& zonename, const std::string& qname, bool auth) {
+
+    if(f_lua_updatednssecorderandauth == 0) {
+
+       if(logging)
+           L << Logger::Info << backend_name << "(updateDNSSECOrderAndAuth) domain_id: '" << domain_id << "' zonename: '" << zonename << "' qname: '" << qname << "' auth: '" << auth << "'" << endl;
+           
+       string ins=toLower(labelReverse(makeRelative(qname, zonename)));
+       return this->updateDNSSECOrderAndAuthAbsolute(domain_id, qname, ins, auth);
+       
+    } 
+
+    if(logging)
+        L << Logger::Info << backend_name << "(updateDNSSECOrderAndAuth) BEGIN domain_id: '" << domain_id << "' zonename: '" << zonename << "' qname: '" << qname << "' auth: '" << auth << "'" << endl;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_updatednssecorderandauth);
+
+    lua_pushnumber(lua, domain_id);
+    lua_pushstring(lua, zonename.c_str());
+    lua_pushstring(lua, qname.c_str());
+    lua_pushboolean(lua, auth);
+
+    if(lua_pcall(lua, 4, 1, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return false;
+    }
+    
+    size_t returnedwhat = lua_type(lua, -1);
+    bool ok = false;
+    
+    if (returnedwhat == LUA_TBOOLEAN)
+        ok = lua_toboolean(lua, -1);
+    
+    lua_pop(lua, 1);
+
+    if(logging)
+        L << Logger::Info << backend_name << "(updateDNSSECOrderAndAuth) END" << endl;
+    
+    return ok;
+}
+
+bool LUABackend::updateDNSSECOrderAndAuthAbsolute(uint32_t domain_id, const std::string& qname, const std::string& ordername, bool auth) {
+
+    if(f_lua_updatednssecorderandauthabsolute == 0)
+       return false;
+       
+    if(logging)
+        L << Logger::Info << backend_name << "(updateDNSSECOrderAndAuthAbsolute) BEGIN domain_id: '" << domain_id << "' qname: '" << qname << "' ordername: '" << ordername << "' auth: '" << auth << "'" << endl;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_updatednssecorderandauthabsolute);
+
+    lua_pushnumber(lua, domain_id);
+    lua_pushstring(lua, qname.c_str());
+    lua_pushstring(lua, ordername.c_str());
+    lua_pushboolean(lua, auth);
+
+    if(lua_pcall(lua, 4, 1, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return false;
+    }
+    
+    size_t returnedwhat = lua_type(lua, -1);
+    bool ok = false;
+    
+    if (returnedwhat == LUA_TBOOLEAN)
+        ok = lua_toboolean(lua, -1);
+    
+    lua_pop(lua, 1);
+
+    if(logging)
+        L << Logger::Info << backend_name << "(updateDNSSECOrderAndAuthAbsolute) END" << endl;
+
+    return ok;
+}
+
+bool LUABackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, std::string& unhashed, std::string& before, std::string& after) {
+
+    if(f_lua_getbeforeandafternamesabsolute == 0)
+       return false;
+
+    unhashed.clear(); 
+    before.clear(); 
+    after.clear();
+
+    if(logging)
+       L << Logger::Info << backend_name << "(getBeforeAndAfterNamesAbsolute) BEGIN id: '" << id << "' qname: '" << qname << "'" << endl;
+       
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_updatednssecorderandauthabsolute);
+
+    lua_pushnumber(lua, id);
+    lua_pushstring(lua, qname.c_str());
+
+    if(lua_pcall(lua, 2, 3, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return false;
+    }
+    
+    size_t returnedwhat = lua_type(lua, -1);
+    bool ok = returnedwhat == LUA_TSTRING;
+    
+    if (!ok) {
+       if(logging)
+           L << Logger::Info << backend_name << "(getBeforeAndAfterNamesAbsolute) ERROR!" << endl;
+           
+       return false;
+    }
+    
+    //will this be correct since we are poping one at the time?
+    unhashed = lua_tostring(lua, -1);
+    lua_pop(lua, 1);
+
+    returnedwhat = lua_type(lua, -1);
+    ok = (returnedwhat == LUA_TSTRING) && ok;
+    
+    before = lua_tostring(lua, -1);
+    lua_pop(lua, 1);
+
+    returnedwhat = lua_type(lua, -1);
+    ok = (returnedwhat == LUA_TSTRING) && ok;
+    
+    after = lua_tostring(lua, -1);
+    lua_pop(lua, 1);
+
+    if(logging)
+        L << Logger::Info << backend_name << "(getBeforeAndAfterNamesAbsolute) END unhashed: '" << unhashed << "' before: '" << before << "' after: '" << after << "' " << endl;
+    
+    return ok;
+}
+
+bool LUABackend::updateDomainKey(const string& name, unsigned int &id, bool toowhat ) {
+
+    if(f_lua_updatedomainkey == 0) 
+       return false;
+
+    if(logging)
+       L << Logger::Info << backend_name << "(updateDomainKey) BEGIN name: '" << name << "' id: '" << id << "' toowhat: '" << toowhat << "'" << endl;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_updatedomainkey);
+
+    lua_pushstring(lua, name.c_str());
+    lua_pushnumber(lua, id);
+    lua_pushboolean(lua, toowhat);
+
+    if(lua_pcall(lua, 3, 1, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return false;
+    }
+    
+    size_t returnedwhat = lua_type(lua, -1);
+    bool ok = false;
+    
+    if (returnedwhat == LUA_TBOOLEAN)
+        ok = lua_toboolean(lua, -1);
+    
+    lua_pop(lua, 1);
+
+    if(logging)
+       L << Logger::Info << backend_name << "(updateDomainKey) END" << endl;
+       
+    return ok;
+}
+
+bool LUABackend::activateDomainKey(const string& name, unsigned int id) {
+
+    if(f_lua_activatedomainkey == 0) 
+       return updateDomainKey(name, id, true);
+
+    if(logging)
+       L << Logger::Info << backend_name << "(activateDomainKey) BEGIN name: '" << name << "' id: '" << id << endl;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_activatedomainkey);
+
+    lua_pushstring(lua, name.c_str());
+    lua_pushnumber(lua, id);
+
+    if(lua_pcall(lua, 2, 1, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return false;
+    }
+    
+    size_t returnedwhat = lua_type(lua, -1);
+    bool ok = false;
+    
+    if (returnedwhat == LUA_TBOOLEAN)
+        ok = lua_toboolean(lua, -1);
+    
+    lua_pop(lua, 1);
+
+    if(logging)
+       L << Logger::Info << backend_name << "(activateDomainKey) END" << endl;
+       
+    return ok;
+}
+
+bool LUABackend::deactivateDomainKey(const string& name, unsigned int id) {
+
+    if(f_lua_deactivatedomainkey == 0) 
+       return updateDomainKey(name, id, false);
+
+    if(logging)
+       L << Logger::Info << backend_name << "(deactivateDomainKey) BEGIN name: '" << name << "' id: '" << id << endl;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_deactivatedomainkey);
+
+    lua_pushstring(lua, name.c_str());
+    lua_pushnumber(lua, id);
+
+    if(lua_pcall(lua, 2, 1, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return false;
+    }
+    
+    size_t returnedwhat = lua_type(lua, -1);
+    bool ok = false;
+    
+    if (returnedwhat == LUA_TBOOLEAN)
+        ok = lua_toboolean(lua, -1);
+    
+    lua_pop(lua, 1);
+
+    if(logging)
+       L << Logger::Info << backend_name << "(deactivateDomainKey) END" << endl;
+       
+    return ok;
+}
+
+bool LUABackend::removeDomainKey(const string& name, unsigned int id) {
+
+    if(f_lua_removedomainkey == 0) 
+       return false;
+
+    if(logging)
+       L << Logger::Info << backend_name << "(removeDomainKey) BEGIN name: '" << name << "' id: '" << id << endl;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_removedomainkey);
+
+    lua_pushstring(lua, name.c_str());
+    lua_pushnumber(lua, id);
+
+    if(lua_pcall(lua, 2, 1, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return false;
+    }
+    
+    size_t returnedwhat = lua_type(lua, -1);
+    bool ok = false;
+    
+    if (returnedwhat == LUA_TBOOLEAN)
+        ok = lua_toboolean(lua, -1);
+    
+    lua_pop(lua, 1);
+
+    if(logging)
+       L << Logger::Info << backend_name << "(removeDomainKey) END" << endl;
+       
+    return ok;
+}
+
+int LUABackend::addDomainKey(const string& name, const KeyData& key) {
+// there is no logging function in pdnssec when running this routine?
+
+//key = id, flags, active, content
+
+    if(f_lua_adddomainkey == 0) 
+       return -1;
+
+    if(logging)
+       //L << Logger::Info << backend_name << "(addDomainKey) BEGIN name: '" << name << "' id: '" << id << endl;
+       cerr << backend_name << "(addDomainKey) BEGIN name: '" << name << endl;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_adddomainkey);
+
+    lua_pushstring(lua, name.c_str());
+
+    lua_newtable(lua);
+    
+    lua_pushliteral(lua, "flags");
+    lua_pushnumber(lua, key.flags);
+    lua_settable(lua, -3);
+
+    lua_pushliteral(lua, "active");
+    lua_pushboolean(lua, key.active);
+    lua_settable(lua, -3);
+    
+    lua_pushliteral(lua, "content");
+    lua_pushstring(lua, key.content.c_str());
+    lua_settable(lua, -3);
+
+    if(lua_pcall(lua, 2, 1, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return -1;
+    }
+
+    size_t returnedwhat = lua_type(lua, -1);
+    int ok = -1;
+    
+    if (returnedwhat == LUA_TNUMBER)
+        ok = lua_tonumber(lua, -1);
+    
+    lua_pop(lua, 1);
+
+    if(logging)
+       cerr << backend_name << "(addDomainKey) END" << endl;
+       
+    return ok;
+}
+
+bool LUABackend::getDomainKeys(const string& name, unsigned int kind, std::vector<KeyData>& keys) {
+    //what is kind used for?
+
+    if(f_lua_getdomainkeys == 0) 
+       return false;
+
+    if(logging)
+       L << Logger::Info << backend_name << "(getDomainKeys) BEGIN name: '" << name << "' kind: '" << kind << endl;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_getdomainkeys);
+
+    lua_pushstring(lua, name.c_str());
+    lua_pushnumber(lua, kind);
+
+    if(lua_pcall(lua, 2, 1, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return false;
+    }
+
+    size_t returnedwhat = lua_type(lua, -1);
+
+    if (returnedwhat != LUA_TTABLE) {
+       lua_pop(lua, 1);
+       if(logging)
+           L << Logger::Info << backend_name << "(getDomainKeys) ERROR!" << endl;
+           
+       return false;
+    }
+
+    lua_pushnil(lua);  
+
+    int key;
+    int j = 0;
+    
+    while (lua_next(lua, -2)) {
+        returnedwhat = lua_type(lua, -1);
+        if (returnedwhat == LUA_TTABLE) {
+           KeyData kd;
+           bool i,f,a,c = false;
+           
+           i = getValueFromTable(lua, "id", kd.id);
+           f = getValueFromTable(lua, "flags", kd.flags);
+           a = getValueFromTable(lua, "active", kd.active);
+           c = getValueFromTable(lua, "content", kd.content);
+           
+           if (i && f && a && c) {
+               j++;
+               keys.push_back(kd);
+           }
+        }
+
+        lua_pop(lua,1);
+        key = lua_tonumber(lua, -1);
+    }
+
+    if(logging)
+       L << Logger::Info << backend_name << "(getDomainKeys) END" << endl;
+       
+    return j > 0;
+}
+
+bool LUABackend::getTSIGKey(const string& name, string* algorithm, string* content) { 
+
+    if(f_lua_gettsigkey == 0) 
+       return false;
+
+    if(logging)
+       L << Logger::Info << backend_name << "(getTSIGKey) BEGIN name: '" << name << "'" << endl;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_gettsigkey);
+
+    lua_pushstring(lua, name.c_str());
+
+    if(lua_pcall(lua, 1, 2, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return false;
+    }
+
+    if ( (lua_type(lua, -1) != LUA_TSTRING) && (lua_type(lua, -2) != LUA_TSTRING) ) {
+       lua_pop(lua, 2);
+       if(logging)
+           L << Logger::Info << backend_name << "(getTSIGKey) ERROR" << endl;
+       return false;
+    }
+    
+    string a,c = "";
+    
+    a = lua_tostring(lua, -1);
+    lua_pop(lua, 1);
+
+    c  = lua_tostring(lua, -1);
+    lua_pop(lua, 1);
+    
+    *algorithm = a;
+    *content = c;
+    
+    if(logging)
+       L << Logger::Info << backend_name << "(getTSIGKey) END" << endl;
+       
+    return true;
+}
+
+bool LUABackend::setDomainMetadata(const string& name, const std::string& kind, std::vector<std::string>& meta) {
+
+    if(f_lua_setdomainmetadata == 0) 
+       return false;
+
+    if(logging)
+       L << Logger::Info << backend_name << "(setDomainMetadata) BEGIN name: '" << name << "' kind: '" << kind << "'" << endl;
+       
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_setdomainmetadata);
+
+    lua_pushstring(lua, name.c_str());
+    lua_pushstring(lua, kind.c_str());
+
+    lua_newtable(lua);
+    std::vector<std::string>::iterator i;
+
+    int c = 0;
+    
+    for(i = meta.begin(); i<meta.end(); i++ ) {
+       c++;
+       lua_pushnumber(lua, c);
+        lua_pushstring(lua, i->c_str());
+        lua_settable(lua, -3);
+    }
+
+    if(lua_pcall(lua, 3, 1, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return false;
+    }
+
+    size_t returnedwhat = lua_type(lua, -1);
+    bool ok = false;
+    
+    if (returnedwhat == LUA_TBOOLEAN)
+        ok = lua_toboolean(lua, -1);
+    
+    lua_pop(lua, 1);
+
+    if(logging)
+       L << Logger::Info << backend_name << "(setDomainMetadata) END" << endl;
+       
+    return ok;
+
+}
+
+bool LUABackend::getDomainMetadata(const string& name, const std::string& kind, std::vector<std::string>& meta) {
+    if(f_lua_getdomainmetadata == 0) 
+       return false;
+
+    if(logging)
+       L << Logger::Info << backend_name << "(getDomainMetadata) BEGIN name: '" << name << "' kind: '" << kind << "'" << endl;
+       
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_getdomainmetadata);
+
+    lua_pushstring(lua, name.c_str());
+    lua_pushstring(lua, kind.c_str());
+
+    if(lua_pcall(lua, 2, 1, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return false;
+    }
+
+    lua_pushnil(lua);  
+
+    int key;
+    int j = 0;
+    size_t returnedwhat;
+    
+    while (lua_next(lua, -2)) {
+        returnedwhat = lua_type(lua, -1);
+        if (returnedwhat == LUA_TSTRING) {
+           j++;
+           meta.push_back(lua_tostring(lua, -1));
+        }
+
+        lua_pop(lua,1);
+        key = lua_tonumber(lua, -1);
+    }
+
+    if(logging)
+       L << Logger::Info << backend_name << "(getDomainMetadata) END" << endl;
+       
+    return j > 0;
+
+}
+
+void LUABackend::alsoNotifies(const string &domain, set<string> *ips) {
+
+    if(f_lua_alsonotifies == 0) 
+       return;
+
+    if(logging)
+       L << Logger::Info << backend_name << "(alsonotifies) BEGIN domain: '" << domain << "'" << endl;
+       
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_alsonotifies);
+
+    lua_pushstring(lua, domain.c_str());
+
+    if(lua_pcall(lua, 1, 1, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return;
+    }
+
+    lua_pushnil(lua);  
+
+    int key;
+    size_t returnedwhat;
+    
+    while (lua_next(lua, -2)) {
+        returnedwhat = lua_type(lua, -1);
+        if (returnedwhat == LUA_TSTRING) {
+           ips->insert(lua_tostring(lua, -1));
+        }
+
+        lua_pop(lua,1);
+        key = lua_tonumber(lua, -1);
+    }
+
+    if(logging)
+       L << Logger::Info << backend_name << "(alsoNotifies) END" << endl;
+       
+    return;
+
+}
diff --git a/modules/luabackend/lua_functions.cc b/modules/luabackend/lua_functions.cc
new file mode 100644 (file)
index 0000000..b30c13f
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+    Copyright (C) 2011 Fredrik Danerklint
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License version 2 as published 
+    by the Free Software Foundation
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#define LUABACKEND_EXTERN_F_HH
+
+#include "luabackend.hh"
+
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+#include "pdns/dnspacket.hh"
+
+#include <iostream>
+#include <sstream>
+using namespace std;
+
+const luaL_Reg lualibs[] = {
+    {"", luaopen_base},
+    {LUA_LOADLIBNAME, luaopen_package},
+    {LUA_TABLIBNAME, luaopen_table},
+    {LUA_IOLIBNAME, luaopen_io},
+    {LUA_OSLIBNAME, luaopen_os},
+    {LUA_STRLIBNAME, luaopen_string},
+    {LUA_MATHLIBNAME, luaopen_math},
+    {LUA_DBLIBNAME, luaopen_debug},
+//    {LUA_COLIBNAME, luaopen_coroutine},
+#ifdef USE_LUAJIT    
+    {"bit",     luaopen_bit},
+    {"jit",     luaopen_jit},
+#endif
+    {NULL, NULL}
+};
+
+int my_lua_panic (lua_State *lua) {
+    lua_getfield(lua, LUA_REGISTRYINDEX, "__LUABACKEND"); 
+    LUABackend* lb = (LUABackend*)lua_touserdata(lua, -1);
+    
+    assert(lua == lb->lua);
+    
+    stringstream e;
+    
+    e << lb->backend_name << "LUA PANIC! '" << lua_tostring(lua,-1) << "'" << endl;
+    
+    throw LUAException (e.str());
+    
+    return 0;
+}
+
+int l_arg_get (lua_State *lua) {
+    int i = lua_gettop(lua);
+    if (i < 1)
+       return 0;
+       
+    lua_getfield(lua, LUA_REGISTRYINDEX, "__LUABACKEND"); 
+    LUABackend* lb = (LUABackend*)lua_touserdata(lua, -1);
+
+    string a = lua_tostring(lua, 1);
+
+    if (::arg().isEmpty(a))
+       lua_pushnil(lua);
+    else 
+        lua_pushstring(lua, lb->my_getArg(a).c_str());
+
+    return 1;
+}
+
+int l_arg_mustdo (lua_State *lua) {
+    int i = lua_gettop(lua);
+    if (i < 1)
+       return 0;
+       
+    lua_getfield(lua, LUA_REGISTRYINDEX, "__LUABACKEND"); 
+    LUABackend* lb = (LUABackend*)lua_touserdata(lua, -1);
+    
+    string a = lua_tostring(lua, 1);
+
+    if (::arg().isEmpty(a))
+       lua_pushnil(lua);
+    else 
+        lua_pushboolean(lua, lb->my_mustDo(a));
+
+    return 1;
+}
+
+int l_dnspacket (lua_State *lua) {
+    lua_getfield(lua, LUA_REGISTRYINDEX, "__LUABACKEND"); 
+    LUABackend* lb = (LUABackend*)lua_touserdata(lua, -1);
+
+    if (lb->dnspacket == NULL) {
+       lua_pushnil(lua);
+       
+       return 1;
+    }
+
+    lua_pushstring(lua, lb->dnspacket->getRemote().c_str());
+    lua_pushnumber(lua, lb->dnspacket->getRemotePort());
+    lua_pushstring(lua, lb->dnspacket->getLocal().c_str());
+    
+    return 3;
+}
+
+int l_logger (lua_State *lua) {
+//    assert(lua == lb->lua);
+    
+    lua_getfield(lua, LUA_REGISTRYINDEX, "__LUABACKEND"); 
+    LUABackend* lb = (LUABackend*)lua_touserdata(lua, -1);
+    
+    int i = lua_gettop(lua);
+    if (i < 1)
+       return 0;
+
+    int log_level = 0;
+    stringstream s;
+    int j;
+    const char *ss;
+
+    log_level = lua_tointeger(lua, 1);
+    
+    string space = "";
+    
+    for(j=2; j<=i; j++) {
+       ss = lua_tostring(lua, j);
+       s << space << ss;
+       space = " ";
+    }
+    
+    L.log(lb->backend_name + s.str(), (Logger::Urgency) log_level);
+    
+    return 0;
+}
+
+void register_lua_functions(lua_State *lua) {
+    lua_gc(lua, LUA_GCSTOP, 0);  // stop collector during initialization 
+
+    const luaL_Reg *lib = lualibs;
+    for (; lib->func; lib++) {
+        lua_pushcfunction(lua, lib->func);
+        lua_pushstring(lua, lib->name);
+        lua_call(lua, 1, 0);
+    }
+
+    lua_gc(lua, LUA_GCRESTART, 0);
+
+    lua_pushinteger(lua, Logger::All);
+    lua_setglobal(lua, "log_all");
+
+    lua_pushinteger(lua, Logger::NTLog);
+    lua_setglobal(lua, "log_ntlog");
+
+    lua_pushinteger(lua, Logger::Alert);
+    lua_setglobal(lua, "log_alert");
+
+    lua_pushinteger(lua, Logger::Critical);
+    lua_setglobal(lua, "log_critical");
+
+    lua_pushinteger(lua, Logger::Error);
+    lua_setglobal(lua, "log_error");
+
+    lua_pushinteger(lua, Logger::Warning);
+    lua_setglobal(lua, "log_warning");
+
+    lua_pushinteger(lua, Logger::Notice);
+    lua_setglobal(lua, "log_notice");
+
+    lua_pushinteger(lua, Logger::Info);
+    lua_setglobal(lua, "log_info");
+    
+    lua_pushinteger(lua, Logger::Debug);
+    lua_setglobal(lua, "log_debug");
+
+    lua_pushinteger(lua, Logger::None);
+    lua_setglobal(lua, "log_none");
+    
+    lua_pushcfunction(lua, l_dnspacket);
+    lua_setglobal(lua, "dnspacket");
+    
+    lua_pushcfunction(lua, l_logger);
+    lua_setglobal(lua, "logger");
+
+    lua_pushcfunction(lua, l_arg_get);
+    lua_setglobal(lua, "getarg");
+
+    lua_pushcfunction(lua, l_arg_mustdo);
+    lua_setglobal(lua, "mustdo");
+    
+    lua_newtable(lua);
+    for(vector<QType::namenum>::const_iterator iter = QType::names.begin(); iter != QType::names.end(); ++iter) {
+       lua_pushnumber(lua, iter->second);
+       lua_setfield(lua, -2, iter->first.c_str());
+    }
+    lua_pushnumber(lua, 3);
+    lua_setfield(lua, -2, "NXDOMAIN");
+    lua_setglobal(lua, "QTypes");
+}
+
+bool LUABackend::getValueFromTable(lua_State *lua, const std::string& key, string& value) {
+  lua_pushstring(lua, key.c_str()); 
+  lua_gettable(lua, -2);  
+
+  bool ret = false;
+  
+  if(!lua_isnil(lua, -1)) {
+    value = lua_tostring(lua, -1);
+    ret = true;
+  }
+  
+  lua_pop(lua, 1);
+  
+  return ret;
+}
+
+bool LUABackend::getValueFromTable(lua_State *lua, uint32_t key, string& value) {
+  lua_pushnumber(lua, key); 
+  lua_gettable(lua, -2);  
+
+  bool ret = false;
+  
+  if(!lua_isnil(lua, -1)) {
+    value = lua_tostring(lua, -1);
+    ret = true;
+  }
+  
+  lua_pop(lua, 1);
+  
+  return ret;
+}
+
+bool LUABackend::getValueFromTable(lua_State *lua, const std::string& key, time_t& value) {
+  lua_pushstring(lua, key.c_str()); 
+  lua_gettable(lua, -2);  
+
+  bool ret = false;
+  
+  if(!lua_isnil(lua, -1)) {
+    value = (time_t)lua_tonumber(lua, -1);
+    ret = true;
+  }
+  
+  lua_pop(lua, 1);
+  
+  return ret;
+}
+
+bool LUABackend::getValueFromTable(lua_State *lua, const std::string& key, uint32_t& value) {
+  lua_pushstring(lua, key.c_str()); 
+  lua_gettable(lua, -2);  
+
+  bool ret = false;
+  
+  if(!lua_isnil(lua, -1)) {
+    value = (uint32_t)lua_tonumber(lua, -1);
+    ret = true;
+  }
+  
+  lua_pop(lua, 1);
+  
+  return ret;
+}
+
+bool LUABackend::getValueFromTable(lua_State *lua, const std::string& key, uint16_t& value) {
+  lua_pushstring(lua, key.c_str()); 
+  lua_gettable(lua, -2);  
+
+  bool ret = false;
+  
+  if(!lua_isnil(lua, -1)) {
+    value = (uint16_t)lua_tonumber(lua, -1);
+    ret = true;
+  }
+  
+  lua_pop(lua, 1);
+  
+  return ret;
+}
+
+bool LUABackend::getValueFromTable(lua_State *lua, const std::string& key, int& value) {
+  lua_pushstring(lua, key.c_str()); 
+  lua_gettable(lua, -2);  
+
+  bool ret = false;
+  
+  if(!lua_isnil(lua, -1)) {
+    value = (int)lua_tonumber(lua, -1);
+    ret = true;
+  }
+  
+  lua_pop(lua, 1);
+  
+  return ret;
+}
+
+bool LUABackend::getValueFromTable(lua_State *lua, const std::string& key, bool& value) {
+  lua_pushstring(lua, key.c_str()); 
+  lua_gettable(lua, -2);  
+
+  bool ret = false;
+  
+  if(!lua_isnil(lua, -1)) {
+    value = lua_toboolean(lua, -1);
+    ret = true;
+  }
+  
+  lua_pop(lua, 1);
+  
+  return ret;
+}
+
diff --git a/modules/luabackend/lua_functions.hh b/modules/luabackend/lua_functions.hh
new file mode 100644 (file)
index 0000000..6d56980
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef LUABACKEND_EXTERN_F_HH
+#define LUABACKEND_EXTERN_F_HH
+
+//extern LUABackend* lb;
+extern int my_lua_panic(lua_State* lua);
+extern void register_lua_functions(lua_State* lua);
+
+#endif 
diff --git a/modules/luabackend/luabackend.cc b/modules/luabackend/luabackend.cc
new file mode 100644 (file)
index 0000000..3e4bf3d
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+    Copyright (C) 2011 Fredrik Danerklint
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License version 2 as published 
+    by the Free Software Foundation
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#include "luabackend.hh"
+#include "pdns/logger.hh"
+
+/* SECOND PART */
+
+class LUAFactory : public BackendFactory
+{
+public:
+  LUAFactory() : BackendFactory("lua") {}
+  
+  void declareArguments(const string &suffix="")
+  {
+  
+    declare(suffix,"filename","Filename of the script for lua backend","powerdns-luabackend.lua");
+    declare(suffix,"logging-query","Logging of the LUA Backend","no");
+
+  }
+  
+  DNSBackend *make(const string &suffix="")
+  {
+    return new LUABackend(suffix);
+  }
+  
+};
+
+/* THIRD PART */
+
+class LUALoader
+{
+public:
+  LUALoader()
+  {
+    BackendMakers().report(new LUAFactory);
+    
+    L<<Logger::Notice<<"[LUABackend] This is the luabackend ("__DATE__", "__TIME__") reporting"<<endl;
+  }  
+};
+
+static LUALoader luaLoader;
diff --git a/modules/luabackend/luabackend.hh b/modules/luabackend/luabackend.hh
new file mode 100644 (file)
index 0000000..6e65aa7
--- /dev/null
@@ -0,0 +1,229 @@
+#ifndef LUABACKEND_HH
+#define LUABACKEND_HH
+
+#include "lua.hpp"
+
+//extern "C" {
+//#include "lua.h"
+//#include "lualib.h"
+//#include "lauxlib.h"
+//}
+
+#include "pdns/dnsbackend.hh"
+
+#undef VERSION
+#include <string>
+using std::string;
+
+//#undef L
+
+
+
+class LUAException {
+public:
+  LUAException(const string &ex) : what(ex){}
+  string what;
+};
+
+class LUABackend : public DNSBackend {
+
+public:
+
+//  MINIMAL BACKEND
+
+    LUABackend(const string &suffix="");
+    ~LUABackend();
+    bool list(const string &target, int domain_id);
+    void lookup(const QType &qtype, const string &qname, DNSPacket *p, int domain_id);
+    bool get(DNSResourceRecord &rr);
+    //! fills the soadata struct with the SOA details. Returns false if there is no SOA.
+    bool getSOA(const string &name, SOAData &soadata, DNSPacket *p=0);
+
+
+//  MASTER BACKEND
+
+    void getUpdatedMasters(vector<DomainInfo>* domains);
+    void setNotifed(int id, u_int32_t serial);
+
+
+//  SLAVE BACKEND
+    bool getDomainInfo(const string &domain, DomainInfo &di);
+    bool isMaster(const string &name, const string &ip);
+    void getUnfreshSlaveInfos(vector<DomainInfo>* domains);
+    void setFresh(int id);
+
+    bool startTransaction(const string &qname, int id);
+    bool commitTransaction();
+    bool abortTransaction();
+    bool feedRecord(const DNSResourceRecord &rr);
+
+
+//  SUPERMASTER BACKEND
+
+    bool superMasterBackend(const string &ip, const string &domain, const vector<DNSResourceRecord>&nsset, string *account, DNSBackend **db);
+    bool createSlaveDomain(const string &ip, const string &domain, const string &account);
+
+
+//  DNSSEC BACKEND
+
+    //! get a list of IP addresses that should also be notified for a domain
+    void alsoNotifies(const string &domain, set<string> *ips);
+    bool getDomainMetadata(const string& name, const std::string& kind, std::vector<std::string>& meta);
+    bool setDomainMetadata(const string& name, const std::string& kind, std::vector<std::string>& meta);
+
+    bool getDomainKeys(const string& name, unsigned int kind, std::vector<KeyData>& keys);
+    bool removeDomainKey(const string& name, unsigned int id);
+    bool activateDomainKey(const string& name, unsigned int id);
+    bool deactivateDomainKey(const string& name, unsigned int id);
+    bool getTSIGKey(const string& name, string* algorithm, string* content);
+    int addDomainKey(const string& name, const KeyData& key);
+
+    bool getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, std::string& unhashed, std::string& before, std::string& after);
+    bool updateDNSSECOrderAndAuthAbsolute(uint32_t domain_id, const std::string& qname, const std::string& ordername, bool auth);
+    bool updateDNSSECOrderAndAuth(uint32_t domain_id, const std::string& zonename, const std::string& qname, bool auth);
+  
+//  OTHER
+    void reload();
+    void rediscover(string* status=0);
+    
+
+    string backend_name;
+    lua_State *lua;
+    DNSPacket *dnspacket;
+
+    //private.cc
+    string my_getArg(string a);
+    bool my_mustDo(string a);
+
+private:
+
+    pthread_t backend_pid;
+    unsigned int backend_count;
+    
+    int f_lua_exec_error;
+    
+    //mininal functions....
+    int f_lua_list;
+    int f_lua_lookup;
+    int f_lua_get;
+    int f_lua_getsoa;
+    
+    //master functions....
+    int f_lua_getupdatedmasters;
+    int f_lua_setnotifed;
+
+    //slave functions....
+    int f_lua_getdomaininfo;
+    int f_lua_ismaster;
+    int f_lua_getunfreshslaveinfos;
+    int f_lua_setfresh;
+
+    int f_lua_starttransaction;
+    int f_lua_committransaction;
+    int f_lua_aborttransaction;
+    int f_lua_feedrecord;
+
+    //supermaster functions....
+    int f_lua_supermasterbackend;
+    int f_lua_createslavedomain;
+
+    //rediscover
+    int f_lua_rediscover;
+
+    //dnssec
+    int f_lua_alsonotifies;
+    int f_lua_getdomainmetadata;
+    int f_lua_setdomainmetadata;
+
+    int f_lua_getdomainkeys;
+    int f_lua_removedomainkey;
+    int f_lua_activatedomainkey;
+    int f_lua_deactivatedomainkey;
+    int f_lua_updatedomainkey;
+    int f_lua_gettsigkey;
+    int f_lua_adddomainkey;
+
+    int f_lua_getbeforeandafternamesabsolute;
+    int f_lua_updatednssecorderandauthabsolute;
+    int f_lua_updatednssecorderandauth;
+
+
+//    int my_lua_panic (lua_State *lua);
+
+//  FUNCTIONS TO THIS BACKEND
+    bool getValueFromTable(lua_State *lua, const std::string& key, string& value);
+    bool getValueFromTable(lua_State *lua, uint32_t key, string& value);
+    bool getValueFromTable(lua_State *lua, const std::string& key, time_t& value);
+    bool getValueFromTable(lua_State *lua, const std::string& key, uint32_t& value);
+    bool getValueFromTable(lua_State *lua, const std::string& key, uint16_t& value);
+    bool getValueFromTable(lua_State *lua, const std::string& key, int& value);
+    bool getValueFromTable(lua_State *lua, const std::string& key, bool& value);
+
+    //private.cc
+    bool domaininfo_from_table(DomainInfo *di);
+    void domains_from_table(vector<DomainInfo>* domains, const char *f_name);
+    void dnsrr_to_table(lua_State *lua, const DNSResourceRecord *rr);
+
+    //reload.cc
+    void get_lua_function(lua_State *lua, const char *name, int *function); 
+
+    bool dnssec;
+
+    bool logging;
+
+    //dnssec.cc
+    bool updateDomainKey(const string& name, unsigned int &id, bool toowhat);
+
+
+/*
+    //minimal.cc
+    bool content(DNSResourceRecord* rr);
+    
+    void getTheFreshOnes(vector<DomainInfo>* domains, string *type, string *f_name);
+    bool checkDomainInfo(const string *domain, mongo::BSONObj *mongo_r, string *f_name, string *mongo_q, DomainInfo *di, SOAData *soadata = NULL);
+    
+    
+    //crc32.cc
+    int generateCRC32(const string& my_string);
+    
+    string mongo_db;
+    string collection_domains;
+    string collection_records;
+
+    string collection_domainmetadata;
+    string collection_cryptokeys;
+    string collection_tsigkeys;
+
+    mongo::DBClientConnection m_db;
+    
+    auto_ptr<mongo::DBClientCursor> cursor;
+    
+    string q_name;
+    
+//    long long unsigned int count;
+    mongo::Query mongo_query;
+    mongo::BSONObj mongo_record;
+    bool elements;
+    DNSResourceRecord rr_record;
+    string type;
+    mongo::BSONObjIterator* contents;
+    
+    
+    
+    unsigned int default_ttl;
+
+    bool logging_cerr;
+    bool logging_content;
+
+    bool checkindex;
+
+    bool use_default_ttl;
+    
+    bool axfr_soa;
+    SOAData last_soadata;
+*/    
+};
+
+#endif 
diff --git a/modules/luabackend/master.cc b/modules/luabackend/master.cc
new file mode 100644 (file)
index 0000000..559e63f
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+    Copyright (C) 2011 Fredrik Danerklint
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License version 2 as published 
+    by the Free Software Foundation
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+
+#include "luabackend.hh"
+
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+
+/* 
+    virtual void getUpdatedMasters(vector<DomainInfo>* domains);
+    virtual void setNotifed(int id, u_int32_t serial);
+*/
+
+void LUABackend::getUpdatedMasters(vector<DomainInfo>* domains) {
+       
+    if (f_lua_getupdatedmasters == 0)
+       return;
+
+    if (logging)
+       L << Logger::Info << backend_name << "(getUpdatedMasters) BEGIN" << endl;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_getupdatedmasters);
+
+    if(lua_pcall(lua, 0, 1, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return;
+    }
+
+    size_t returnedwhat = lua_type(lua, -1);
+    if (returnedwhat != LUA_TTABLE) {
+        lua_pop(lua, 1 );
+        return;
+    }
+    
+    domains_from_table(domains, "getUpdatedMasters");
+    
+    if (logging)
+       L << Logger::Info << backend_name << "(getUpdatedMasters) END" << endl;
+}
+
+void LUABackend::setNotifed(int id, u_int32_t serial) {
+       
+    if (f_lua_setnotifed == 0)
+       return;
+
+    if (logging)
+       L << Logger::Info << backend_name << "(setNotifed) BEGIN" << endl;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_setnotifed);
+
+    lua_pushnumber(lua, id);
+    lua_pushnumber(lua, serial);
+
+    if(lua_pcall(lua, 2, 0, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return;
+    }
+
+    if (logging)
+       L << Logger::Info << backend_name << "(setNotifed) END" << endl;
+}
+
diff --git a/modules/luabackend/minimal.cc b/modules/luabackend/minimal.cc
new file mode 100644 (file)
index 0000000..1bf9cfe
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+    Copyright (C) 2011 Fredrik Danerklint
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License version 2 as published 
+    by the Free Software Foundation
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#include "luabackend.hh"
+
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+
+//#include "lua_functions.hh"
+
+/* FIRST PART */
+
+LUABackend::LUABackend(const string &suffix) {
+
+    setArgPrefix("lua"+suffix);
+    
+    try {
+
+       if (pthread_equal(backend_pid, pthread_self())) {
+           backend_count++;
+       } else {
+           backend_count = 1;
+           backend_pid = pthread_self();
+       }
+       
+//     lb = NULL;
+       lua = NULL;
+       dnspacket = NULL;
+       dnssec = false;
+
+       reload();
+    }
+
+    catch(LUAException &e) {
+        L<<Logger::Error<<backend_name<<"Error: "<<e.what<<endl;
+        throw AhuException(e.what);
+    }
+
+}
+  
+LUABackend::~LUABackend() {
+    L<<Logger::Info<<backend_name<<"Closeing..." << endl;
+    
+    lua_close(lua);
+}
+
+bool LUABackend::list(const string &target, int domain_id) {
+    if (logging)
+       L << Logger::Info << backend_name << "(list) BEGIN" << endl;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_list);
+
+    lua_pushstring(lua, target.c_str());
+    lua_pushnumber(lua, domain_id);
+
+    if(lua_pcall(lua, 2, 1, f_lua_exec_error) != 0) {
+       string e = backend_name + lua_tostring(lua, -1);
+       lua_pop(lua, 1);
+       
+       throw runtime_error(e);
+       return false;
+    }
+    
+    size_t returnedwhat = lua_type(lua, -1);
+    bool ok = false;
+    
+    if (returnedwhat == LUA_TBOOLEAN)
+       ok = lua_toboolean(lua, -1);
+    
+    lua_pop(lua, 1);
+
+    if (logging)
+       L << Logger::Info << backend_name << "(list) END" << endl;
+       
+    return ok;
+}
+    
+void LUABackend::lookup(const QType &qtype, const string &qname, DNSPacket *p, int domain_id) {
+    if (logging)
+       L << Logger::Info << backend_name << "(lookup) BEGIN" << endl;
+
+    dnspacket = p;
+    
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_lookup);
+
+//    lua_pushnumber(lua, qtype.getCode());
+    lua_pushstring(lua, qtype.getName().c_str());
+    lua_pushstring(lua, qname.c_str());
+    lua_pushnumber(lua, domain_id);
+
+    if(lua_pcall(lua, 3, 0, f_lua_exec_error) != 0) {
+       string e = backend_name + lua_tostring(lua, -1);
+       lua_pop(lua, 1);
+       
+       dnspacket = NULL;
+       
+       throw runtime_error(e);
+       return;
+    }
+    
+    dnspacket = NULL;
+    
+    if (logging)
+       L << Logger::Info << backend_name << "(lookup) END" << endl;
+}
+
+bool LUABackend::get(DNSResourceRecord &rr) {
+    if (logging)
+       L << Logger::Info << backend_name << "(get) BEGIN" << endl;
+    
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_get);
+    
+    if(lua_pcall(lua, 0, 1, f_lua_exec_error) != 0) {
+       string e = backend_name + lua_tostring(lua, -1);
+       lua_pop(lua, 1);
+       
+       throw runtime_error(e);
+       return false;
+    }
+    
+    size_t returnedwhat = lua_type(lua, -1);
+    if (returnedwhat != LUA_TTABLE) {
+       lua_pop(lua, 1 );
+       return false;
+    }
+    
+    rr.content.clear();
+    
+//    uint16_t qt;
+    string qt;
+    
+    if (getValueFromTable(lua, "type", qt) )
+       rr.qtype = qt;
+    getValueFromTable(lua, "name", rr.qname);
+    getValueFromTable(lua, "domain_id", rr.domain_id);
+    getValueFromTable(lua, "auth", rr.auth);
+    getValueFromTable(lua, "last_modified", rr.last_modified);
+    getValueFromTable(lua, "priority", rr.priority);
+
+    getValueFromTable(lua, "ttl", rr.ttl);
+    if (rr.ttl == 0) 
+        rr.ttl = ::arg().asNum( "default-ttl" );
+    
+    getValueFromTable(lua, "content", rr.content);
+
+    lua_pop(lua, 1 );
+    
+    if (logging)
+       L << Logger::Info << backend_name << "(get) END" << endl;
+       
+    return !rr.content.empty();
+}
+
+bool LUABackend::getSOA(const string &name, SOAData &soadata, DNSPacket *p) {
+    if (logging)
+       L << Logger::Info << backend_name << "(getsoa) BEGIN" << endl;
+    
+    dnspacket = p;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_getsoa);
+    
+    lua_pushstring(lua, name.c_str());
+    
+    if(lua_pcall(lua, 1, 1, f_lua_exec_error) != 0) {
+       string e = backend_name + lua_tostring(lua, -1);
+       lua_pop(lua, 1);
+       
+       dnspacket = NULL;
+       
+       throw runtime_error(e);
+       return false;
+    }
+    
+    dnspacket = NULL;
+    
+    size_t returnedwhat = lua_type(lua, -1);
+    if (returnedwhat != LUA_TTABLE) {
+       lua_pop(lua, 1 );
+       return false;
+    }
+
+    soadata.db = this;
+    soadata.serial = 0;
+    getValueFromTable(lua, "serial", soadata.serial);
+    if (soadata.serial == 0) {
+       lua_pop(lua, 1 );
+       return false;
+    }
+    
+    getValueFromTable(lua, "refresh", soadata.refresh);
+    getValueFromTable(lua, "retry", soadata.retry);
+    getValueFromTable(lua, "expire", soadata.expire);
+    getValueFromTable(lua, "default_ttl", soadata.default_ttl);
+    getValueFromTable(lua, "domain_id", soadata.domain_id);
+                    
+    getValueFromTable(lua, "ttl", soadata.ttl);
+    if (soadata.ttl == 0 && soadata.default_ttl > 0) 
+       soadata.ttl = soadata.default_ttl;
+       
+    if (soadata.ttl == 0) {
+       lua_pop(lua, 1 );
+       return false;
+    }
+    
+    if (!getValueFromTable(lua, "nameserver", soadata.nameserver)) {
+       soadata.nameserver = arg()["default-soa-name"];
+        if (soadata.nameserver.empty()) {
+           L<<Logger::Error << backend_name << "(getSOA)" << " Error: SOA Record is missing nameserver for the domain '" << name << "'" << endl; 
+           lua_pop(lua, 1 );
+            return false;
+        }
+    }
+    
+    if (!getValueFromTable(lua, "hostmaster", soadata.hostmaster))
+       soadata.hostmaster = "hostmaster." + name;
+
+    lua_pop(lua, 1 );
+
+    if (logging)
+       L << Logger::Info << backend_name << "(getsoa) END" << endl;
+       
+    return true;
+}
diff --git a/modules/luabackend/private.cc b/modules/luabackend/private.cc
new file mode 100644 (file)
index 0000000..1858d0f
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+    Copyright (C) 2011 Fredrik Danerklint
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License version 2 as published 
+    by the Free Software Foundation
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#include "luabackend.hh"
+
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+
+string LUABackend::my_getArg(string a) {
+    return getArg(a);
+}
+
+bool LUABackend::my_mustDo(string a) {
+    return mustDo(a);
+}
+
+bool LUABackend::domaininfo_from_table(DomainInfo *di) {
+
+    di->backend = NULL;
+    
+    if (!getValueFromTable(lua, "id", di->id))
+       return false;
+       
+    if (!getValueFromTable(lua, "zone", di->zone))
+       return false;
+       
+    if (!getValueFromTable(lua, "serial", di->serial))
+       return false;
+       
+    getValueFromTable(lua, "notified_serial", di->notified_serial);
+    getValueFromTable(lua, "last_check", di->last_check);
+    
+    di->kind = DomainInfo::Native;
+    
+    string kind;
+    if (getValueFromTable(lua, "kind", kind)) {
+    
+       if (kind == "MASTER")
+           di->kind = DomainInfo::Master;
+       else if (kind == "SLAVE")
+           di->kind = DomainInfo::Slave;
+    }
+
+    lua_pushstring(lua, "masters"); 
+    lua_gettable(lua, -2);  
+
+    if(!lua_isnil(lua, -1)) {
+       lua_pushnil(lua);  
+       const char *key, *value;
+       while (lua_next(lua, -2)) {
+           value = lua_tostring(lua, -1);
+           lua_pop(lua,1);
+           key = lua_tostring(lua, -1); 
+
+           di->masters.push_back(value);
+       }    
+    }
+  
+    lua_pop(lua, 1);
+    
+    di->backend = this;
+
+    return true;
+}
+
+void LUABackend::domains_from_table(vector<DomainInfo>* domains, const char *f_name) {
+    lua_pushnil(lua);  
+
+    int k;
+    size_t returnedwhat;
+    
+    while (lua_next(lua, -2)) {
+        returnedwhat = lua_type(lua, -1);
+        if (returnedwhat == LUA_TTABLE) {
+            DomainInfo di;
+
+            if (domaininfo_from_table(&di)) 
+                domains->push_back(di);
+        }
+
+        lua_pop(lua,1);
+        k = lua_tonumber(lua, -1);
+    }
+}
+
+
+void LUABackend::dnsrr_to_table(lua_State *lua, const DNSResourceRecord *rr) {
+
+    lua_newtable(lua);
+    
+    lua_pushliteral(lua, "qtype");
+    lua_pushstring(lua, rr->qtype.getName().c_str());
+    lua_settable(lua, -3);
+    
+    lua_pushliteral(lua, "qclass");
+    lua_pushnumber(lua, rr->qclass);
+    lua_settable(lua, -3);
+    
+    lua_pushliteral(lua, "priority");
+    lua_pushnumber(lua, rr->priority);
+    lua_settable(lua, -3);
+
+    lua_pushliteral(lua, "ttl");
+    lua_pushnumber(lua, rr->ttl);
+    lua_settable(lua, -3);
+
+    lua_pushliteral(lua, "auth");
+    lua_pushboolean(lua, rr->auth);
+    lua_settable(lua, -3);
+    
+    lua_pushliteral(lua, "content");
+    lua_pushstring(lua, rr->content.c_str());
+    lua_settable(lua, -3);
+    
+}
\ No newline at end of file
diff --git a/modules/luabackend/reload.cc b/modules/luabackend/reload.cc
new file mode 100644 (file)
index 0000000..6e143aa
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+    Copyright (C) 2011 Fredrik Danerklint
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License version 2 as published 
+    by the Free Software Foundation
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+
+#include "luabackend.hh"
+
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+
+#include <iostream>
+#include <sstream>
+using namespace std;
+
+#include "lua_functions.hh"
+
+/* 
+    virtual void reload();
+    virtual void rediscover(string* status=0);
+*/
+
+void LUABackend::get_lua_function(lua_State *lua, const char *name, int *function) {
+    *function = 0;
+    
+    string f = "f_";
+    f.append(name);
+    
+    string arg = "";
+    if (!::arg().isEmpty(f))
+        arg = getArg(f);
+
+    lua_getglobal(lua, arg == "" ? name : arg.c_str());
+    if (!lua_isnil(lua, -1)) {
+       lua_pushvalue(lua, -1);     
+        *function = luaL_ref(lua, LUA_REGISTRYINDEX);
+    }
+}
+
+
+void LUABackend::reload() {
+    
+    backend_name.clear();
+
+//     backend_name = "[LUABackend: " + uitoa(backend_pid) + " (" + uitoa(backend_count) +")] ";
+    backend_name = "[LUABackend: (" + uitoa(backend_count) +")] ";
+    
+    if (lua)
+       lua_close(lua);
+       
+    logging = ::arg().mustDo("query-logging") || mustDo("logging-query");
+    
+    lua = lua_open();
+    
+    if (lua != NULL) {
+       lua_atpanic(lua, my_lua_panic);
+       
+       string filename = getArg("filename"); //"powerdns-luabackend.lua";
+       
+       if (luaL_loadfile (lua, filename.c_str()) != 0) {
+           stringstream e;
+           e << backend_name << "Error loading the file '" << filename << "' : " << lua_tostring(lua,-1) << endl;
+
+           lua_pop(lua, 1);
+           throw LUAException (e.str());
+       } else {
+       
+           lua_pushlightuserdata(lua, (void*)this); 
+           lua_setfield(lua, LUA_REGISTRYINDEX, "__LUABACKEND");
+           
+           register_lua_functions(lua);
+           
+           if(lua_pcall(lua,  0, 0, 0)) { 
+               stringstream e;
+               e << backend_name << "Error running the file '" << filename << "' : " << lua_tostring(lua,-1) << endl;
+
+               lua_pop(lua, 1);
+               throw LUAException (e.str());
+
+           } else {
+               get_lua_function(lua, "exec_error", &f_lua_exec_error);
+               
+               //minimal functions....
+               get_lua_function(lua, "list", &f_lua_list);
+               get_lua_function(lua, "lookup", &f_lua_lookup);
+               get_lua_function(lua, "get", &f_lua_get);
+               get_lua_function(lua, "getsoa", &f_lua_getsoa);
+               
+               if (f_lua_list == 0 || f_lua_lookup == 0 || f_lua_get == 0 || f_lua_getsoa == 0) {
+                       throw LUAException (backend_name + "MINIMAL BACKEND: Missing requried function(s)!");
+               }
+               
+               //master functions....
+               get_lua_function(lua, "getupdatedmasters", &f_lua_getupdatedmasters);
+               get_lua_function(lua, "setnotifed", &f_lua_setnotifed);
+               
+               //slave functions....
+               get_lua_function(lua, "getdomaininfo", &f_lua_getdomaininfo);
+               get_lua_function(lua, "ismaster", &f_lua_ismaster);
+               get_lua_function(lua, "getunfreshslaveinfos", &f_lua_getunfreshslaveinfos);
+               get_lua_function(lua, "setfresh", &f_lua_setfresh);
+               get_lua_function(lua, "starttransaction", &f_lua_starttransaction);
+               get_lua_function(lua, "committransaction", &f_lua_committransaction);
+               get_lua_function(lua, "aborttransaction", &f_lua_aborttransaction);
+               get_lua_function(lua, "feedrecord", &f_lua_feedrecord);
+
+               //supermaster functions....
+               get_lua_function(lua, "supermasterbackend", &f_lua_supermasterbackend);
+               get_lua_function(lua, "createslavedomain", &f_lua_createslavedomain);
+               
+               //rediscover
+               get_lua_function(lua, "rediscover", &f_lua_rediscover);
+               
+                //dnssec
+               get_lua_function(lua, "alsonotifies", &f_lua_alsonotifies);
+               get_lua_function(lua, "getdomainmetadata", &f_lua_getdomainmetadata);
+               get_lua_function(lua, "setdomainmetadata", &f_lua_setdomainmetadata);
+
+               get_lua_function(lua, "getdomainkeys", &f_lua_getdomainkeys);
+               get_lua_function(lua, "removedomainkey", &f_lua_removedomainkey);
+               get_lua_function(lua, "activatedomainkey", &f_lua_activatedomainkey);
+               get_lua_function(lua, "deactivatedomainkey", &f_lua_deactivatedomainkey);
+               get_lua_function(lua, "updatedomainkey", &f_lua_updatedomainkey);
+               get_lua_function(lua, "adddomainkey", &f_lua_adddomainkey);
+
+               get_lua_function(lua, "gettsigkey", &f_lua_gettsigkey);
+               get_lua_function(lua, "getbeforeandafternamesabsolute", &f_lua_getbeforeandafternamesabsolute);
+               get_lua_function(lua, "updatednssecorderandauthabsolute", &f_lua_updatednssecorderandauthabsolute);
+               get_lua_function(lua, "updatednssecorderandauth", &f_lua_updatednssecorderandauth); // not needed...
+
+           }
+       }
+    } else {
+       //a big kaboom here!
+       throw LUAException (backend_name + "LUA OPEN FAILED!");
+    }
+}
+
+void LUABackend::rediscover(string* status) {
+    if (logging)
+       L << Logger::Info << backend_name << "(rediscover) BEGIN" << endl;
+    
+    if (f_lua_rediscover == 0)
+        return;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_rediscover);
+
+    if(lua_pcall(lua, 0, 1, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return;
+    }
+
+    size_t returnedwhat = lua_type(lua, -1);
+    if (returnedwhat != LUA_TSTRING) {
+        lua_pop(lua, 1 );
+        return;
+    }
+
+    string s = lua_tostring(lua, -1);
+    lua_pop(lua, 1 );
+    *status = s;
+    
+    if (logging)
+       L << Logger::Info << backend_name << "(rediscover) END" << endl;
+       
+    return;
+}
+
diff --git a/modules/luabackend/slave.cc b/modules/luabackend/slave.cc
new file mode 100644 (file)
index 0000000..a77b64e
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+    Copyright (C) 2011 Fredrik Danerklint
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License version 2 as published 
+    by the Free Software Foundation
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+
+#include "luabackend.hh"
+
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+
+/* 
+    
+   virtual bool startTransaction(const string &qname, int id);
+   virtual bool commitTransaction();
+   virtual bool abortTransaction();
+   virtual bool feedRecord(const DNSResourceRecord &rr);
+
+   virtual bool getDomainInfo(const string &domain, DomainInfo &di);
+   virtual bool isMaster(const string &name, const string &ip);
+   virtual void getUnfreshSlaveInfos(vector<DomainInfo>* domains);
+   virtual void setFresh(int id);
+*/
+
+bool LUABackend::startTransaction(const string &qname, int id) {
+
+    if (f_lua_starttransaction == 0)
+        return false;
+
+    if (logging)
+        L << Logger::Info << backend_name << "(startTransaction) BEGIN" << endl;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_starttransaction);
+
+    lua_pushstring(lua, qname.c_str());
+    lua_pushnumber(lua, id);
+
+    if(lua_pcall(lua, 2, 1, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return false;
+    }
+
+    size_t returnedwhat = lua_type(lua, -1);
+    bool ok = false;
+    
+    if (returnedwhat == LUA_TBOOLEAN)
+        ok = lua_toboolean(lua, -1);
+    
+    lua_pop(lua, 1);
+    
+    if (logging)
+       L << Logger::Info << backend_name << "(startTransaction) END" << endl;
+       
+    return ok;
+}
+
+bool LUABackend::commitTransaction() {
+
+    if (f_lua_committransaction == 0)
+        return false;
+        
+    if (logging)
+       L << Logger::Info << backend_name << "(commitTransaction) BEGIN" << endl;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_committransaction);
+
+    if(lua_pcall(lua, 0, 1, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return false;
+    }
+
+    size_t returnedwhat = lua_type(lua, -1);
+    bool ok = false;
+    
+    if (returnedwhat == LUA_TBOOLEAN)
+        ok = lua_toboolean(lua, -1);
+    
+    lua_pop(lua, 1);
+    
+    if (logging)
+       L << Logger::Info << backend_name << "(commitTransaction) END" << endl;
+       
+    return ok;
+}
+
+bool LUABackend::abortTransaction() {
+
+    if (f_lua_aborttransaction == 0)
+        return false;
+
+    if (logging)
+       L << Logger::Info << backend_name << "(abortTransaction) BEGIN" << endl;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_aborttransaction);
+
+    if(lua_pcall(lua, 0, 1, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return false;
+    }
+
+    size_t returnedwhat = lua_type(lua, -1);
+    bool ok = false;
+    
+    if (returnedwhat == LUA_TBOOLEAN)
+        ok = lua_toboolean(lua, -1);
+    
+    lua_pop(lua, 1);
+
+    if (logging)
+       L << Logger::Info << backend_name << "(abortTransaction) END" << endl;
+    return ok;
+}
+
+bool LUABackend::feedRecord(const DNSResourceRecord &rr) {
+
+    if (f_lua_feedrecord == 0)
+        return false;
+
+    if (logging)
+       L << Logger::Info << backend_name << "(feedRecord) BEGIN" << endl;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_feedrecord);
+    dnsrr_to_table(lua, &rr);
+
+    if(lua_pcall(lua, 1, 1, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return false;
+    }
+
+    size_t returnedwhat = lua_type(lua, -1);
+    bool ok = false;
+    
+    if (returnedwhat == LUA_TBOOLEAN)
+        ok = lua_toboolean(lua, -1);
+    
+    lua_pop(lua, 1);
+
+    if (logging)
+       L << Logger::Info << backend_name << "(feedRecord) END" << endl;
+       
+    return ok;
+}
+
+void LUABackend::setFresh(int id) {
+    
+    if (f_lua_setfresh == 0)
+        return;
+
+    if (logging)
+       L << Logger::Info << backend_name << "(setFresh) BEGIN" << endl;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_setfresh);
+
+    lua_pushnumber(lua, id);
+
+    if(lua_pcall(lua, 1, 0, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return;
+    }
+
+    if (logging)
+       L << Logger::Info << backend_name << "(setFresh) END" << endl;
+
+}
+
+void LUABackend::getUnfreshSlaveInfos(vector<DomainInfo>* domains) {
+    
+    if (f_lua_getunfreshslaveinfos == 0)
+        return;
+
+    if (logging)
+       L << Logger::Info << backend_name << "(getUnfreshSlaveInfos) BEGIN" << endl;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_getunfreshslaveinfos);
+
+    if(lua_pcall(lua, 0, 1, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return;
+    }
+
+    size_t returnedwhat = lua_type(lua, -1);
+    if (returnedwhat != LUA_TTABLE) {
+        lua_pop(lua, 1 );
+        return;
+    }
+    
+    domains_from_table(domains, "getUnfreshSlaveInfos");
+    
+    if (logging)
+       L << Logger::Info << backend_name << "(getUnfreshSlaveInfos) END" << endl;
+
+}
+
+bool LUABackend::isMaster(const string &domain, const string &ip) {
+       
+    if (f_lua_ismaster == 0)
+        return false;
+
+    if (logging)
+       L << Logger::Error << backend_name << "(isMaster) BEGIN" << endl;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_ismaster);
+
+    lua_pushstring(lua, domain.c_str());
+    lua_pushstring(lua, ip.c_str());
+    
+    if(lua_pcall(lua, 2, 1, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return false;
+    }
+
+    size_t returnedwhat = lua_type(lua, -1);
+    bool ok = false;
+    
+    if (returnedwhat == LUA_TBOOLEAN)
+        ok = lua_toboolean(lua, -1);
+    
+    lua_pop(lua, 1);
+    
+    if (logging)
+       L << Logger::Info << backend_name << "(isMaster) END" << endl;
+
+    return ok;
+}
+
+bool LUABackend::getDomainInfo(const string &domain, DomainInfo &di) {
+    if (f_lua_getdomaininfo == 0)
+        return false;
+
+    if (logging)
+       L << Logger::Info << backend_name << "(getDomainInfo) BEGIN" << endl;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_getdomaininfo);
+
+    lua_pushstring(lua, domain.c_str());
+    
+    if(lua_pcall(lua, 1, 1, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return false;
+    }
+
+    size_t returnedwhat = lua_type(lua, -1);
+    if (returnedwhat != LUA_TTABLE) {
+        lua_pop(lua, 1 );
+        return false;
+    }
+
+    if (logging)
+       L << Logger::Info << backend_name << "(getDomainInfo) END" << endl;
+       
+    return domaininfo_from_table(&di);
+}
diff --git a/modules/luabackend/supermaster.cc b/modules/luabackend/supermaster.cc
new file mode 100644 (file)
index 0000000..fa6cc0d
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+    Copyright (C) 2011 Fredrik Danerklint
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License version 2 as published 
+    by the Free Software Foundation
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+
+#include "luabackend.hh"
+
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+
+/* 
+ //! determine if ip is a supermaster or a domain
+  virtual bool superMasterBackend(const string &ip, const string &domain, const vector<DNSResourceRecord>&nsset, string *account, DNSBackend **db)
+
+  //! called by PowerDNS to create a slave record for a superMaster
+  virtual bool createSlaveDomain(const string &ip, const string &domain, const string &account)
+
+*/
+
+bool LUABackend::superMasterBackend(const string &ip, const string &domain, const vector<DNSResourceRecord>&nsset, string *account, DNSBackend **db) {
+       
+    if (f_lua_supermasterbackend == 0)
+        return false;
+
+    if (logging)
+       L << Logger::Info << backend_name << "(superMasterBackend) BEGIN" << endl;
+       
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_supermasterbackend);
+
+    lua_pushstring(lua, ip.c_str());
+    lua_pushstring(lua, domain.c_str());
+    
+    
+    lua_newtable(lua);
+    int c = 0;
+    for(vector<DNSResourceRecord>::const_iterator i=nsset.begin();i!=nsset.end();++i) {
+       c++;
+       lua_pushnumber(lua, c);
+       
+       DNSResourceRecord rr;
+       
+       rr.qtype = i->qtype;
+       rr.qclass = i->qclass;
+       rr.priority = i->priority;
+       rr.ttl = i->ttl;
+       rr.auth = i->auth;
+       rr.content = i->content;
+       
+       dnsrr_to_table(lua, &rr);
+       lua_settable(lua, -3);
+    }
+    
+    if(lua_pcall(lua, 3, 2, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return false;
+    }
+
+    size_t returnedwhat = lua_type(lua, -1);
+    bool ok = false;
+    
+    if (returnedwhat == LUA_TBOOLEAN)
+        ok = lua_toboolean(lua, -1);
+    
+    lua_pop(lua, 1);
+
+    string a = "";
+    returnedwhat = lua_type(lua, -1);
+    if (returnedwhat == LUA_TSTRING)
+       a = lua_tostring(lua, -1);
+    lua_pop(lua, 1);
+    
+    if (ok) {
+       *account = a;
+       *db = this;
+    }
+    
+    if (logging)
+       L << Logger::Info << backend_name << "(superMasterBackend) END" << endl;
+       
+    return ok;
+}
+
+bool LUABackend::createSlaveDomain(const string &ip, const string &domain, const string &account) {
+       
+    if (f_lua_createslavedomain == 0)
+        return false;
+
+    if (logging)
+       L << Logger::Info << backend_name << "(createSlaveDomain) BEGIN" << endl;
+
+    lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_createslavedomain);
+
+    lua_pushstring(lua, ip.c_str());
+    lua_pushstring(lua, domain.c_str());
+    lua_pushstring(lua, account.c_str());
+
+    if(lua_pcall(lua, 3, 1, f_lua_exec_error) != 0) {
+        string e = backend_name + lua_tostring(lua, -1);
+        lua_pop(lua, 1);
+
+        throw runtime_error(e);
+        return false;
+    }
+
+    size_t returnedwhat = lua_type(lua, -1);
+    bool ok = false;
+    
+    if (returnedwhat == LUA_TBOOLEAN)
+        ok = lua_toboolean(lua, -1);
+    
+    lua_pop(lua, 1);
+
+    if (logging)
+       L << Logger::Info << backend_name << "(createSlaveDomain) END" << endl;
+       
+    return ok;
+}
diff --git a/modules/luabackend/test/dnsperf b/modules/luabackend/test/dnsperf
new file mode 100755 (executable)
index 0000000..c4ba0e7
--- /dev/null
@@ -0,0 +1 @@
+../../../../../src/dnsperf-src-1.0.1.0-1/dnsperf -d one -p5300 -H10 -T1 -l60
diff --git a/modules/luabackend/test/one b/modules/luabackend/test/one
new file mode 100644 (file)
index 0000000..7d137cc
--- /dev/null
@@ -0,0 +1,2 @@
+www.test.com ANY
+
diff --git a/modules/luabackend/test/pdns b/modules/luabackend/test/pdns
new file mode 100755 (executable)
index 0000000..95df2d0
--- /dev/null
@@ -0,0 +1,4 @@
+../../../pdns/pdns_server --daemon=no --local-port=5300 --socket-dir=./  \
+--no-shuffle --launch=lua \
+--fancy-records --send-root-referral --loglevel=9 \
+--config-dir=./ --cache-ttl=0 --negquery-cache-ttl=0 --query-cache-ttl=0 --recursive-cache-ttl=0 
\ No newline at end of file
diff --git a/modules/luabackend/test/pdns.conf b/modules/luabackend/test/pdns.conf
new file mode 100644 (file)
index 0000000..5b03502
--- /dev/null
@@ -0,0 +1,340 @@
+# Autogenerated configuration file template
+#################################
+# allow-axfr-ips       Allow zonetransfers only to these subnets
+#
+# allow-axfr-ips=0.0.0.0/0
+
+#################################
+# allow-recursion      List of subnets that are allowed to recurse
+#
+# allow-recursion=0.0.0.0/0
+
+#################################
+# allow-recursion-override     Set this so that local data fully overrides the recursor
+#
+# allow-recursion-override=no
+
+#################################
+# cache-ttl    Seconds to store packets in the PacketCache
+#
+# cache-ttl=20
+
+#################################
+# chroot       If set, chroot to this directory for more security
+#
+# chroot=
+
+#################################
+# config-dir   Location of configuration directory (pdns.conf)
+#
+# config-dir=/usr/local/etc
+
+#################################
+# config-name  Name of this virtual configuration - will rename the binary image
+#
+# config-name=
+
+#################################
+# control-console      Debugging switch - don't use
+#
+# control-console=no
+
+#################################
+# daemon       Operate as a daemon
+#
+# daemon=no
+
+#################################
+# default-soa-name     name to insert in the SOA record if none set in the backend
+#
+# default-soa-name=a.misconfigured.powerdns.server
+
+#################################
+# default-ttl  Seconds a result is valid if not set otherwise
+#
+# default-ttl=3600
+
+#################################
+# disable-axfr Disable zonetransfers but do allow TCP queries
+#
+# disable-axfr=no
+
+#################################
+# disable-tcp  Do not listen to TCP queries
+#
+# disable-tcp=no
+
+#################################
+# distributor-threads  Default number of Distributor (backend) threads to start
+#
+distributor-threads=3
+
+#################################
+# do-ipv6-additional-processing        Do AAAA additional processing
+#
+do-ipv6-additional-processing=yes
+
+#################################
+# fancy-records        Process URL and MBOXFW records
+#
+# fancy-records=no
+
+#################################
+# guardian     Run within a guardian process
+#
+# guardian=no
+
+#################################
+# launch       Which backends to launch and order to query them in
+#
+# launch=
+
+#################################
+# lazy-recursion       Only recurse if question cannot be answered locally
+#
+# lazy-recursion=yes
+
+#################################
+# load-modules Load this module - supply absolute or relative path
+#
+# load-modules=
+
+#################################
+# local-address        Local IP addresses to which we bind
+#
+local-address=127.0.0.1
+
+#################################
+# local-ipv6   Local IP address to which we bind
+#
+local-ipv6=::1
+
+#################################
+# local-port   The port on which we listen
+#
+# local-port=53
+
+#################################
+# log-dns-details      If PDNS should log DNS non-erroneous details
+#
+# log-dns-details=
+
+#################################
+# log-failed-updates   If PDNS should log failed update requests
+#
+# log-failed-updates=
+
+#################################
+# logfile      Logfile to use (Windows only)
+#
+# logfile=pdns.log
+
+#################################
+# logging-facility     Log under a specific facility
+#
+# logging-facility=
+
+#################################
+# loglevel     Amount of logging. Higher is more. Do not set below 3
+#
+# loglevel=4
+
+#################################
+# master       Act as a master
+#
+# master=no
+
+#################################
+# max-queue-length     Maximum queuelength before considering situation lost
+#
+# max-queue-length=5000
+
+#################################
+# max-tcp-connections  Maximum number of TCP connections
+#
+# max-tcp-connections=10
+
+#################################
+# module-dir   Default directory for modules
+#
+# module-dir=/usr/local/lib
+
+#################################
+# negquery-cache-ttl   Seconds to store packets in the PacketCache
+#
+# negquery-cache-ttl=60
+
+#################################
+# no-shuffle   Set this to prevent random shuffling of answers - for regression testing
+#
+# no-shuffle=off
+
+#################################
+# out-of-zone-additional-processing    Do out of zone additional processing
+#
+# out-of-zone-additional-processing=yes
+
+#################################
+# pipebackend-abi-version      Version of the pipe backend ABI
+#
+# pipebackend-abi-version=1
+
+#################################
+# query-cache-ttl      Seconds to store packets in the PacketCache
+#
+# query-cache-ttl=20
+
+#################################
+# query-local-address  Source IP address for sending queries
+#
+# query-local-address=
+
+#################################
+# query-logging        Hint backends that queries should be logged
+#
+# query-logging=no
+
+#################################
+# queue-limit  Maximum number of milliseconds to queue a query
+#
+# queue-limit=1500
+
+#################################
+# recursive-cache-ttl  Seconds to store packets in the PacketCache
+#
+# recursive-cache-ttl=10
+
+#################################
+# recursor     If recursion is desired, IP address of a recursing nameserver
+#
+# recursor=no
+
+#################################
+# send-root-referral   Send out old-fashioned root-referral instead of ServFail in case of no authority
+#
+# send-root-referral=no
+
+#################################
+# setgid       If set, change group id to this gid for more security
+#
+# setgid=
+
+#################################
+# setuid       If set, change user id to this uid for more security
+#
+# setuid=
+
+#################################
+# skip-cname   Do not perform CNAME indirection for each query
+#
+# skip-cname=no
+
+#################################
+# slave        Act as a slave
+#
+# slave=no
+
+#################################
+# slave-cycle-interval Reschedule failed SOA serial checks once every .. seconds
+#
+# slave-cycle-interval=60
+
+#################################
+# smtpredirector       Our smtpredir MX host
+#
+# smtpredirector=a.misconfigured.powerdns.smtp.server
+
+#################################
+# soa-expire-default   Default SOA expire
+#
+# soa-expire-default=604800
+
+#################################
+# soa-minimum-ttl      Default SOA mininum ttl
+#
+# soa-minimum-ttl=3600
+
+#################################
+# soa-refresh-default  Default SOA refresh
+#
+# soa-refresh-default=10800
+
+#################################
+# soa-retry-default    Default SOA retry
+#
+# soa-retry-default=3600
+
+#################################
+# soa-serial-offset    Make sure that no SOA serial is less than this number
+#
+# soa-serial-offset=0
+
+#################################
+# socket-dir   Where the controlsocket will live
+#
+# socket-dir=/var/run
+
+#################################
+# strict-rfc-axfrs     Perform strictly rfc compliant axfrs (very slow)
+#
+# strict-rfc-axfrs=no
+
+#################################
+# trusted-notification-proxy   IP address of incoming notification proxy
+#
+# trusted-notification-proxy=
+
+#################################
+# urlredirector        Where we send hosts to that need to be url redirected
+#
+# urlredirector=127.0.0.1
+
+#################################
+# use-logfile  Use a log file (Windows only)
+#
+# use-logfile=no
+
+#################################
+# version-string       PowerDNS version in packets - full, anonymous, powerdns or custom
+#
+# version-string=full
+
+#################################
+# webserver    Start a webserver for monitoring
+#
+# webserver=no
+
+#################################
+# webserver-address    IP Address of webserver to listen on
+#
+# webserver-address=127.0.0.1
+
+#################################
+# webserver-password   Password required for accessing the webserver
+#
+# webserver-password=
+
+#################################
+# webserver-port       Port of webserver to listen on
+#
+# webserver-port=8081
+
+#################################
+# webserver-print-arguments    If the webserver should print arguments
+#
+# webserver-print-arguments=no
+
+#################################
+# wildcard-url Process URL and MBOXFW records
+#
+# wildcard-url=no
+
+#################################
+# wildcards    Honor wildcards in the database
+#
+# wildcards=
+
+
+#query-logging=yes
+launch=lua
+
diff --git a/modules/luabackend/test/pdns.pid b/modules/luabackend/test/pdns.pid
new file mode 100644 (file)
index 0000000..479fd61
--- /dev/null
@@ -0,0 +1 @@
+6283
diff --git a/modules/luabackend/test/pdnssec b/modules/luabackend/test/pdnssec
new file mode 100755 (executable)
index 0000000..1d6a2b3
--- /dev/null
@@ -0,0 +1 @@
+../../../pdns/pdnssec --config-dir=./ $@
diff --git a/modules/luabackend/test/powerdns-luabackend.lua b/modules/luabackend/test/powerdns-luabackend.lua
new file mode 100644 (file)
index 0000000..6ee9d94
--- /dev/null
@@ -0,0 +1,112 @@
+--remember, this is just a test case to see that the minimal backend does work...
+
+local logger = logger
+local pairs = pairs
+local type = type
+
+local log_error = log_error
+local dnspacket = dnspacket
+
+
+local domains_id = {}
+local domains_name = {}
+local records = {}
+
+
+domains_name["test.com"] = {domain_id = 11, name = "test.com", type = "NATIVE", soa = { hostmaster = "ahu.test.com", nameserver = "ns1.test.com", serial = 2005092501, refresh = 28800, retry = 7200, expire = 604800, default_ttl = 86400, ttl = 3600 } }
+domains_id["11"] = domains_name["test.com"] 
+
+
+records["test.com"] = { 
+    {domain_id = 11, name = "test.com", type = "NS", ttl = 120, content = "ns1.test.com"},
+    {domain_id = 11, name = "test.com", type = "NS", ttl = 120, content = "ns2.test.com"},
+}
+records["ns1.test.com"] = {
+    {domain_id = 11, name = "ns1.test.com", type = "A", ttl = 120, content = "10.11.12.14"},
+    {domain_id = 11, name = "ns1.test.com", type = "AAAA", ttl = 120, content = "1:2:3:4:5:6:7:9"}
+}
+records["ns2.test.com"] = {
+    {domain_id = 11, name = "ns2.test.com", type = "A", ttl = 120, content = "10.11.12.15"},
+    {domain_id = 11, name = "ns2.test.com", type = "AAAA", ttl = 120, content = "1:2:3:4:5:6:7:10"}
+}
+
+records["www.test.com"] = { {domain_id = 11, name = "www.test.com", type = "CNAME", ttl = 120, content = "host.test.com"} }
+records["host.test.com"] = {
+    {domain_id = 11, name = "host.test.com", type = "A", ttl = 120, content = "10.11.12.13"},
+    {domain_id = 11, name = "host.test.com", type = "AAAA", ttl = 120, content = "1:2:3:4:5:6:7:8"}
+}
+
+
+
+function list(target, domain_id)
+    logger(log_error, "(l_list)", "target:", target, " domain_id:", domain_id )
+    
+    return false
+end
+
+local size, c, r, n, nn, q_type, q_name, domainid
+local remote_ip, remote_port, local_ip
+
+function lookup(qtype, qname, domain_id)
+--    logger(log_error, "(l_lookup)", "qtype:", qtype, " qname:", qname, " domain_id:", domain_id )
+    q_type = qtype
+    q_name = qname
+    domainid = domain_id
+    
+    r = records[q_name]
+    
+    c = 0
+    size = 0
+
+    remote_ip, remote_port, local_ip = dnspacket()
+--    logger(log_error, "(l_lookup) dnspacket", "remote:", remote_ip, " port:", remote_port, " local:", local_ip)
+
+    if type(r) == "table" then
+       size = #r
+    end
+--    logger(log_error, "(l_lookup)", "size:", size)
+end
+
+function get()
+--    logger(log_error, "(l_get) BEGIN")
+
+    while c < size do
+       c = c + 1
+       if (q_type == "ANY" or q_type == r[c]["type"]) then 
+--         for kk,vv in pairs(r[c]) do
+--             logger(log_error, kk, type(vv), vv)
+--         end
+           return r[c]
+       end
+    end
+
+--    logger(log_error, "(l_get) END")
+    return false
+end
+
+local k,v,kk,vv
+
+function getsoa(name)
+--    logger(log_error, "(l_getsoa) BEGIN", "name:", name)
+
+    r = domains_name[name]
+    if type(r) == "table" then
+--     logger(log_error, type(r), type(r["soa"]))
+       return r["soa"] 
+    end
+    
+--    logger(log_error, "(l_getsoa) END NOT FOUND")
+end
+
+logger(log_error, "powerdns-luabackend starting up!")
+
+
+for k,v in pairs(QTypes) do
+--    logger(log_error, k, v)
+end
+
+for k,v in pairs(records) do
+    for kk,vv in pairs(v) do
+--     logger(log_error, kk, type(vv), vv["type"])
+    end
+end