root/trunk/pdns/pdns/lua-pdns-recursor.cc @ 1509

Revision 1509, 6.4 KB (checked in by ahu, 3 years ago)

WARNING WARNING! This changes the Lua/PowerDNS interface in SVN, and restores the 3.1.7.* API!
From now, use getlocaladdress() call to get the address to which a query was sent. Implemented after advice from the ever helpful #lua!

Line 
1#include "lua-pdns-recursor.hh"
2
3#if !defined(PDNS_ENABLE_LUA) && !defined(LIBDIR)
4
5// stub implementation
6
7PowerDNSLua::PowerDNSLua(const std::string& fname)
8{
9  throw runtime_error("Lua support disabled");
10}
11
12bool PowerDNSLua::nxdomain(const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res)
13{
14  return false;
15}
16
17bool PowerDNSLua::preresolve(const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res)
18{
19  return false;
20}
21
22PowerDNSLua::~PowerDNSLua()
23{
24
25}
26
27#else
28
29extern "C" {
30#undef L
31/* Include the Lua API header files. */
32#include <lua.h>
33#include <lauxlib.h>
34#include <lualib.h>
35}
36
37#include <stdlib.h>
38#include <stdio.h>
39#include <string>
40#include <vector>
41#include <stdexcept>
42#include "logger.hh"
43using namespace std;
44
45bool netmaskMatchTable(lua_State* lua, const std::string& ip)
46{
47  lua_pushnil(lua);  /* first key */
48  while (lua_next(lua, 2) != 0) {
49    string netmask=lua_tostring(lua, -1);
50    Netmask nm(netmask);
51    ComboAddress ca(ip);
52    lua_pop(lua, 1);
53   
54    if(nm.match(ip)) 
55      return true;
56  }
57  return false;
58}
59
60extern "C" {
61
62int netmaskMatchLua(lua_State *lua)
63{
64  bool result=false;
65  if(lua_gettop(lua) >= 2) {
66    string ip=lua_tostring(lua, 1);
67    if(lua_istable(lua, 2)) {
68      result = netmaskMatchTable(lua, ip);
69    }
70    else {
71      for(int n=2 ; n <= lua_gettop(lua); ++n) { 
72        string netmask=lua_tostring(lua, n);
73        Netmask nm(netmask);
74        ComboAddress ca(ip);
75       
76        result = nm.match(ip);
77        if(result)
78          break;
79      }
80    }
81  }
82 
83  lua_pushboolean(lua, result);
84  return 1;
85}
86
87int getLocalAddressLua(lua_State* lua)
88{
89  lua_getfield(lua, LUA_REGISTRYINDEX, "__PowerDNSLua"); 
90  PowerDNSLua* pl = (PowerDNSLua*)lua_touserdata(lua, -1);
91 
92  lua_pushstring(lua, pl->getLocal().toString().c_str());
93  return 1;
94}
95
96int logLua(lua_State *lua)
97{
98  if(lua_gettop(lua) >= 1) {
99    string message=lua_tostring(lua, 1);
100    theL()<<Logger::Error<<"From Lua script: "<<message<<endl;
101  }
102  return 0;
103}
104}
105
106PowerDNSLua::PowerDNSLua(const std::string& fname)
107{
108  d_lua = lua_open();
109
110#ifndef LUA_VERSION_NUM
111  luaopen_base(d_lua);
112  luaopen_string(d_lua);
113
114  if(lua_dofile(d_lua,  fname.c_str())) 
115#else
116  luaL_openlibs(d_lua);
117  if(luaL_dofile(d_lua,  fname.c_str())) 
118#endif
119    throw runtime_error(string("Error loading LUA file '")+fname+"': "+ string(lua_isstring(d_lua, -1) ? lua_tostring(d_lua, -1) : "unknown error"));
120
121  lua_settop(d_lua, 0);
122 
123  lua_pushcfunction(d_lua, netmaskMatchLua);
124  lua_setglobal(d_lua, "matchnetmask");
125
126  lua_pushcfunction(d_lua, logLua);
127  lua_setglobal(d_lua, "pdnslog");
128
129  lua_pushcfunction(d_lua, getLocalAddressLua);
130  lua_setglobal(d_lua, "getlocaladdress");
131
132  lua_newtable(d_lua);
133
134  for(vector<QType::namenum>::const_iterator iter = QType::names.begin(); iter != QType::names.end(); ++iter) {
135    lua_pushnumber(d_lua, iter->second);
136    lua_setfield(d_lua, -2, iter->first.c_str());
137  }
138  lua_pushnumber(d_lua, 3);
139  lua_setfield(d_lua, -2, "NXDOMAIN");
140  lua_setglobal(d_lua, "pdns");
141 
142  lua_pushlightuserdata(d_lua, (void*)this); 
143  lua_setfield(d_lua, LUA_REGISTRYINDEX, "__PowerDNSLua");
144}
145
146bool PowerDNSLua::nxdomain(const ComboAddress& remote, const ComboAddress& local,const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res)
147{
148  return passthrough("nxdomain", remote, local, query, qtype, ret, res);
149}
150
151bool PowerDNSLua::preresolve(const ComboAddress& remote, const ComboAddress& local,const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res)
152{
153  return passthrough("preresolve", remote, local, query, qtype, ret, res);
154}
155
156bool PowerDNSLua::getFromTable(const std::string& key, std::string& value)
157{
158  lua_pushstring(d_lua, key.c_str()); // 4 is now '1'
159  lua_gettable(d_lua, -2);  // replace by the first entry of our table we hope
160
161  bool ret=false;
162  if(!lua_isnil(d_lua, -1)) {
163    value = lua_tostring(d_lua, -1);
164    ret=true;
165  }
166  lua_pop(d_lua, 1);
167  return ret;
168}
169
170
171bool PowerDNSLua::getFromTable(const std::string& key, uint32_t& value)
172{
173  lua_pushstring(d_lua, key.c_str()); // 4 is now '1'
174  lua_gettable(d_lua, -2);  // replace by the first entry of our table we hope
175
176  bool ret=false;
177  if(!lua_isnil(d_lua, -1)) {
178    value = (uint32_t)lua_tonumber(d_lua, -1);
179    ret=true;
180  }
181  lua_pop(d_lua, 1);
182  return ret;
183}
184
185
186bool PowerDNSLua::passthrough(const string& func, const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res)
187{
188  lua_getglobal(d_lua,  func.c_str());
189  if(!lua_isfunction(d_lua, -1)) {
190    //  cerr<<"No such function '"<<func<<"'\n";
191    lua_pop(d_lua, 1);
192    return false;
193  }
194 
195  d_local = local;
196  /* the first argument */
197  lua_pushstring(d_lua,  remote.toString().c_str() );
198  lua_pushstring(d_lua,  query.c_str() );
199  lua_pushnumber(d_lua,  qtype.getCode() );
200
201  if(lua_pcall(d_lua,  3, 2, 0)) { // error
202    string error=string("lua error in '"+func+"': ")+lua_tostring(d_lua, -1);
203    lua_pop(d_lua, 1);
204    throw runtime_error(error);
205    return false;
206  }
207  int newres = (int)lua_tonumber(d_lua, 1); // new rcode
208  if(newres < 0) {
209    //    cerr << "handler did not handle"<<endl;
210    lua_pop(d_lua, 2);
211    return false;
212  }
213  res=newres;
214
215  /* get the result */
216  DNSResourceRecord rr;
217  rr.qname = query;
218  rr.d_place = DNSResourceRecord::ANSWER;
219  rr.ttl = 3600;
220
221  ret.clear();
222
223  /*           1       2   3   4   */
224  /* stack:  boolean table key row */
225
226#ifndef LUA_VERSION_NUM
227  int tableLen = luaL_getn(d_lua, 2);
228#else
229  int tableLen = lua_objlen(d_lua, 2);
230#endif
231
232  for(int n=1; n < tableLen + 1; ++n) {
233    lua_pushnumber(d_lua, n);
234    lua_gettable(d_lua, 2);
235
236    uint32_t tmpnum=0;
237    if(!getFromTable("qtype", tmpnum)) 
238      rr.qtype=QType::A;
239    else
240      rr.qtype=tmpnum;
241
242    getFromTable("content", rr.content);
243    if(!getFromTable("ttl", rr.ttl))
244      rr.ttl=3600;
245
246    if(!getFromTable("qname", rr.qname))
247      rr.qname = query;
248
249    if(!getFromTable("place", tmpnum))
250      rr.d_place = DNSResourceRecord::ANSWER;
251    else
252      rr.d_place = (DNSResourceRecord::Place) tmpnum;
253
254    /* removes 'value'; keeps 'key' for next iteration */
255    lua_pop(d_lua, 1); // table
256
257    //    cerr<<"Adding content '"<<rr.content<<"' with place "<<(int)rr.d_place<<" \n";
258    ret.push_back(rr);
259  }
260
261  lua_pop(d_lua, 2);
262
263  return true;
264}
265
266PowerDNSLua::~PowerDNSLua()
267{
268  lua_close(d_lua);
269}
270#endif
Note: See TracBrowser for help on using the browser.