#!/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 \
./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
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 )
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+-llua5.1
\ No newline at end of file
--- /dev/null
+====================================
+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
--- /dev/null
+/*
+ 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;
+
+}
--- /dev/null
+/*
+ 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;
+}
+
--- /dev/null
+#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
--- /dev/null
+/*
+ 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;
--- /dev/null
+#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
--- /dev/null
+/*
+ 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;
+}
+
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+}
+
--- /dev/null
+/*
+ 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);
+}
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+../../../../../src/dnsperf-src-1.0.1.0-1/dnsperf -d one -p5300 -H10 -T1 -l60
--- /dev/null
+www.test.com ANY
+
--- /dev/null
+../../../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
--- /dev/null
+# 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
+
--- /dev/null
+../../../pdns/pdnssec --config-dir=./ $@
--- /dev/null
+--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