]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
first stab at generic asynchronous lookup engine for Lua, with known crasher bugs...
authorbert hubert <bert.hubert@powerdns.com>
Sun, 18 Oct 2015 10:59:31 +0000 (12:59 +0200)
committerbert hubert <bert.hubert@powerdns.com>
Sun, 18 Oct 2015 10:59:31 +0000 (12:59 +0200)
pdns/Makefile.am
pdns/dumresp.cc
pdns/kv-example-script.lua [new file with mode: 0644]
pdns/kvresp.cc [new file with mode: 0644]
pdns/lua-recursor.cc
pdns/lua-recursor.hh
pdns/pdns_recursor.cc

index 8203f0419b5e6d4db1827f7b6dc0a7e77f55fc60..75c2bfc13f9a1a52728c0072cb701b1478cf3268 100644 (file)
@@ -109,6 +109,7 @@ EXTRA_PROGRAMS = \
        dnstcpbench \
        dnswasher \
        dumresp \
+       kvresp \
        notify \
        nproxy \
        nsec3dig \
@@ -532,6 +533,14 @@ dumresp_SOURCES = \
        unix_utility.cc \
        qtype.cc 
 
+kvresp_SOURCES = \
+       dnslabeltext.cc dnsname.cc dnsname.hh \
+       kvresp.cc \
+       logger.cc \
+       misc.cc misc.hh \
+       statbag.cc \
+       unix_utility.cc \
+       qtype.cc 
 
 saxfr_SOURCES = \
        base32.cc \
index 02d08652fd5fac773780f717104ec23ae6a7156c..864f774de19e761a3dc103f0aac8721996cdc432 100644 (file)
@@ -40,12 +40,10 @@ try
     if(len < 0)
       unixDie("recvfrom");
     cout<<"Had packet: "<<string(buffer, len)<<endl;
-    /*
     if(dh->qr)
       continue;
     dh->qr=1;
     dh->ad=0;
-    */
     if(sendto(s.getHandle(), buffer, len, 0,  (struct sockaddr*)&rem, socklen) < 0)
       unixDie("sendto");
 
diff --git a/pdns/kv-example-script.lua b/pdns/kv-example-script.lua
new file mode 100644 (file)
index 0000000..f55fbb9
--- /dev/null
@@ -0,0 +1,45 @@
+
+--[[ 
+This implements a two-step domain filtering solution where the status of an IP address
+and a domain name need to be looked up.
+To do so, we use the udpQuestionResponse answers which generically allows us to do asynchronous
+lookups via UDP.
+Such lookups can be slow, they won't block PowerDNS while we wait for them.
+
+To benefit from this hook, return: "udpQueryResponse", UDP-server, data 
+from preresolve (or other hooks).
+The 'data' third return value should be a table with the query in there, plus the callback
+that needs to be called once the data is in.
+
+We'll add more parameters, like 'timeout' and perhaps 'protocol' as we improve this feature
+over time. 
+--]]
+
+function preresolve ( remoteip, domain, qtype )
+       print ("preresolve handler called for: "..remoteip.. ", local: ".. getlocaladdress()..", ".. domain..", ".. qtype)
+       return "udpQueryResponse", "127.0.0.1:5555", {query="IP "..remoteip, callback="getipdetails"}
+end
+
+function getipdetails(remoteip, domain, qtype, data)
+        print("In getipdetails, got ".. data.response.. " from '"..remoteip.."',  for '"..remoteip.."'")
+        data.ipstatus=data.response
+        data.query="DOMAIN "..domain
+        data.callback="getdomaindetails"
+        return "udpQueryResponse", "127.0.0.1:5555", data
+end
+
+function getdomaindetails(remoteip, domain, qtype, data)
+        print("In getipdetails, got ".. data.response.. " from '"..remoteip.."',  for '"..domain.."'")
+        print("So status of domain is "..data.response.." and status of IP is "..data.ipstatus)
+        if(data.ipstatus=="1" and data.response=="1")
+        then
+               print("IP wants filtering and domain is of the filtered kind")
+               return 0,{{qtype=pdns.CNAME, content="www.blocked.com", ttl=3602},
+                         {qname="www.webserver.com", qtype=pdns.A, content="1.2.3.4", ttl=3602}}
+        else
+               return pdns.PASS, {}
+        end
+end
+
+
+
diff --git a/pdns/kvresp.cc b/pdns/kvresp.cc
new file mode 100644 (file)
index 0000000..89ddeae
--- /dev/null
@@ -0,0 +1,56 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "iputils.hh"
+#include "sstuff.hh"
+#include "statbag.hh"
+
+StatBag S;
+
+int main(int argc, char** argv)
+try
+{
+  if(argc != 3) {
+    cerr<<"Syntax: dumresp local-address local-port"<<endl;
+    exit(EXIT_FAILURE);
+  }
+
+  ComboAddress local(argv[1], atoi(argv[2]));
+  Socket s(local.sin4.sin_family, SOCK_DGRAM);  
+
+  s.bind(local);
+  cout<<"Bound to "<<local.toStringWithPort()<<endl;
+
+  char buffer[1500];
+
+  int len;
+  ComboAddress rem=local;
+  socklen_t socklen = rem.getSocklen();
+  for(;;) {
+    len=recvfrom(s.getHandle(), buffer, sizeof(buffer), 0, (struct sockaddr*)&rem, &socklen);
+    if(len < 0)
+      unixDie("recvfrom");
+    string query(buffer, len);
+    cout<<"Had packet: "<<query<<endl;
+    vector<string> parts;
+    stringtok(parts, query);
+    if(parts.size()<2)
+      continue;
+    string response;
+    if(parts[0]=="DOMAIN") 
+      response=  (parts[1].find("xxx") != string::npos) ? "1" : "0";
+    else if(parts[0]=="IP")
+      response=  (parts[1]=="127.0.0.1") ? "1" : "0";
+    else
+      response= "???";
+
+    cout<<"Our reply: "<<response<<endl; 
+    if(sendto(s.getHandle(), response.c_str(), response.length(), 0,  (struct sockaddr*)&rem, socklen) < 0)
+      unixDie("sendto");
+  }
+}
+catch(std::exception& e)
+{
+  cerr<<"Fatal error: "<<e.what()<<endl;
+  exit(EXIT_FAILURE);
+}
index 8aba70b2890a8a0aaefbbbdb3a39949eec6b730d..5a790963eb313b7956c8535e8c2db74d5da30675 100644 (file)
@@ -228,22 +228,6 @@ bool RecursorLua::ipfilter(const ComboAddress& remote, const ComboAddress& local
   return newres != -1;
 }
 
-static bool getFromTable(lua_State *lua, const std::string &key, lua_CFunction& value)
-{
-  lua_pushstring(lua, key.c_str()); // 4 is now '1'
-  lua_gettable(lua, -2);  // replace by the first entry of our table we hope
-
-  bool ret=false;
-
-  if(lua_isfunction(lua, -1)) {
-    value = lua_tocfunction(lua, -1);
-    ret=true;
-  }
-  lua_pop(lua, 1);
-  return ret;
-}
-
-
 bool RecursorLua::passthrough(const string& func, const ComboAddress& remote, const ComboAddress& local, const DNSName& query, const QType& qtype, vector<DNSRecord>& ret,
   int& res, bool* variable)
 {
@@ -289,7 +273,7 @@ bool RecursorLua::passthrough(const string& func, const ComboAddress& remote, co
     throw runtime_error(error);
     return false;
   }
-
+ loop:;
   if(variable)
     *variable |= d_variable;
 
@@ -297,36 +281,37 @@ bool RecursorLua::passthrough(const string& func, const ComboAddress& remote, co
     string tocall = lua_tostring(d_lua,1);
     lua_remove(d_lua, 1); // the name
     ret.clear();
-    cerr<<"tocall: "<<tocall<<endl;
-    if(tocall == "udpQuestionResponse") {
-      
+    if(tocall == "udpQueryResponse") {
       string dest = lua_tostring(d_lua,1);
-      cerr<<"dest: "<<dest<<endl;
       string uquery;
       getFromTable("query", uquery);
-      lua_CFunction callback=0;
-      cout<<"callback get:"<<::getFromTable(d_lua, "callback", callback)<<endl;
-      cout<<"callback value: "<<(void*)callback<<endl;
-      cerr<<"query: "<<query<<endl;
-      //      string followup = lua_tostring(d_lua, 3);
-      // cerr<<"followup: "<<dest<<endl;
-      lua_pop(d_lua, 3);
-
-      string answer = udpQuestionResponse(ComboAddress(dest), uquery);
-      cerr<<"Back in lua-recursor, got: '"<<answer<<"'"<<endl;
-      lua_pushcfunction(d_lua, callback);
+      string callback;
+      getFromTable("callback", callback);
+
+      lua_remove(d_lua, -2);
+
+      // XXX THIS IS PLAIN WRONG - WE LEAVE STUFF ON THE LUA STACK AND EXPECT IT TO STILL BE HERE WHEN WE GET BACK!
+      string answer = GenUDPQueryResponse(ComboAddress(dest), uquery);
+
+      lua_getglobal(d_lua,  callback.c_str());
+      
       lua_pushstring(d_lua,  remote.toString().c_str() );
       lua_pushstring(d_lua,  query.toString().c_str() );
       lua_pushnumber(d_lua,  qtype.getCode() );
-      lua_pushstring(d_lua,  answer.c_str() );
-      cerr<<"Going to call"<<endl;
+
+      lua_pushvalue(d_lua, -5);
+      lua_remove(d_lua, -6);
+
+      lua_pushstring(d_lua, answer.c_str());
+      lua_setfield(d_lua, -2, "response");
+
       if(lua_pcall(d_lua,  4, 3, 0)) {   // NOTE! Means we always get 3 stack entries back, no matter what our lua hook returned!
        string error=string("lua error in '"+func+"' while callback for '"+query.toString()+"|"+qtype.getName()+": ")+lua_tostring(d_lua, -1);
        lua_pop(d_lua, 1);
        throw runtime_error(error);
        return false;
       }
-      cerr<<"We called!"<<endl;
+      goto loop;
     }
     else if(tocall == "getFakeAAAARecords") {
       string luaprefix = lua_tostring(d_lua, 2);
index e63945fcb07089eaa892b15924b6988cc8ccbd27..23b975c23b8da8bf52a167fbc7d204cbaa7f3e36 100644 (file)
@@ -3,7 +3,7 @@
 #include "dns.hh"
 #include "iputils.hh"
 #include "lua-pdns.hh"
-string udpQuestionResponse(const ComboAddress& dest, const string& query);
+string GenUDPQueryResponse(const ComboAddress& dest, const string& query);
 class RecursorLua : public PowerDNSLua
 {
 public:
index 1aa506437afd52fd9e9daff9475577a6697d7cdb..79f02b2ff6fa3e6ce74c62d9fd728ef9b23cc254 100644 (file)
@@ -230,57 +230,52 @@ int arecvtcp(string& data, int len, Socket* sock, bool incompleteOkay)
   return ret;
 }
 
-void handleUDPQueryResponse(int fd, FDMultiplexer::funcparam_t& var)
+void handleGenUDPQueryResponse(int fd, FDMultiplexer::funcparam_t& var)
 {
-  cerr<<"In handle UDPQueryResponse"<<endl;
-  PacketID* pident=any_cast<PacketID>(&var);
+  PacketID pident=*any_cast<PacketID>(&var);
   char resp[512];
   int ret=recv(fd, resp, sizeof(resp), 0);
   t_fdm->removeReadFD(fd);
   if(ret >= 0) {
     string data(resp, ret);
-    cerr<<"Reporting what we got ('"<<data<<"')"<<endl;
-    cerr<<"Reporting returned: "<<MT->sendEvent(*pident, &data)<<endl;
+    MT->sendEvent(pident, &data);
   }
   else {
-    cerr<<"Had some kind of error: "<<ret<<endl;
+    string empty;
+    MT->sendEvent(pident, &empty);
+    //    cerr<<"Had some kind of error: "<<ret<<", "<<strerror(errno)<<endl;
   }
 }
-string udpQuestionResponse(const ComboAddress& dest, const string& query)
+string GenUDPQueryResponse(const ComboAddress& dest, const string& query)
 {
-  cerr<<"In udpQuestionResponse"<<endl;
   Socket s(dest.sin4.sin_family, SOCK_DGRAM);
   s.setNonBlocking();
   ComboAddress local = getQueryLocalAddress(dest.sin4.sin_family, 0);
   
   s.bind(local);
   s.connect(dest);
-  cerr<<"here, query="<<query<<endl;
   s.send(query);
 
   PacketID pident;
   pident.sock=&s;
   pident.type=0;
-  t_fdm->addReadFD(s.getHandle(), handleUDPQueryResponse, pident);
+  t_fdm->addReadFD(s.getHandle(), handleGenUDPQueryResponse, pident);
 
   string data;
-  cerr<<"Entering waitEvent in udpQuestionResponse"<<endl;
   int ret=MT->waitEvent(pident,&data, g_networkTimeoutMsec);
-  cerr<<"Got back: "<<data<<endl; 
   if(!ret || ret==-1) { // timeout
-    cerr<<"Got back some kind of error, ret="<<ret<<endl;
     t_fdm->removeReadFD(s.getHandle());
   }
   else if(data.empty()) {// error, EOF or other
-
+    // we could special case this
     return data;
   }
-
   return data;
 }
 
 
-
 vector<ComboAddress> g_localQueryAddresses4, g_localQueryAddresses6;
 const ComboAddress g_local4("0.0.0.0"), g_local6("::");