| 1 | #include "lua-pdns-recursor.hh" |
|---|
| 2 | |
|---|
| 3 | #if !defined(PDNS_ENABLE_LUA) && !defined(LIBDIR) |
|---|
| 4 | |
|---|
| 5 | // stub implementation |
|---|
| 6 | |
|---|
| 7 | PowerDNSLua::PowerDNSLua(const std::string& fname) |
|---|
| 8 | { |
|---|
| 9 | throw runtime_error("Lua support disabled"); |
|---|
| 10 | } |
|---|
| 11 | |
|---|
| 12 | bool 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 | |
|---|
| 17 | bool 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 | |
|---|
| 22 | PowerDNSLua::~PowerDNSLua() |
|---|
| 23 | { |
|---|
| 24 | |
|---|
| 25 | } |
|---|
| 26 | |
|---|
| 27 | #else |
|---|
| 28 | |
|---|
| 29 | extern "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" |
|---|
| 43 | using namespace std; |
|---|
| 44 | |
|---|
| 45 | bool 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 | |
|---|
| 60 | extern "C" { |
|---|
| 61 | |
|---|
| 62 | int 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 | |
|---|
| 87 | int logLua(lua_State *lua) |
|---|
| 88 | { |
|---|
| 89 | if(lua_gettop(lua) >= 1) { |
|---|
| 90 | string message=lua_tostring(lua, 1); |
|---|
| 91 | theL()<<Logger::Error<<"From Lua script: "<<message<<endl; |
|---|
| 92 | } |
|---|
| 93 | return 0; |
|---|
| 94 | } |
|---|
| 95 | } |
|---|
| 96 | |
|---|
| 97 | PowerDNSLua::PowerDNSLua(const std::string& fname) |
|---|
| 98 | { |
|---|
| 99 | d_lua = lua_open(); |
|---|
| 100 | |
|---|
| 101 | #ifndef LUA_VERSION_NUM |
|---|
| 102 | luaopen_base(d_lua); |
|---|
| 103 | luaopen_string(d_lua); |
|---|
| 104 | |
|---|
| 105 | if(lua_dofile(d_lua, fname.c_str())) |
|---|
| 106 | #else |
|---|
| 107 | luaL_openlibs(d_lua); |
|---|
| 108 | if(luaL_dofile(d_lua, fname.c_str())) |
|---|
| 109 | #endif |
|---|
| 110 | throw runtime_error(string("Error loading LUA file '")+fname+"': "+ string(lua_isstring(d_lua, -1) ? lua_tostring(d_lua, -1) : "unknown error")); |
|---|
| 111 | |
|---|
| 112 | lua_settop(d_lua, 0); |
|---|
| 113 | |
|---|
| 114 | lua_pushcfunction(d_lua, netmaskMatchLua); |
|---|
| 115 | lua_setglobal(d_lua, "matchnetmask"); |
|---|
| 116 | |
|---|
| 117 | lua_pushcfunction(d_lua, logLua); |
|---|
| 118 | lua_setglobal(d_lua, "pdnslog"); |
|---|
| 119 | |
|---|
| 120 | lua_newtable(d_lua); |
|---|
| 121 | |
|---|
| 122 | for(vector<QType::namenum>::const_iterator iter = QType::names.begin(); iter != QType::names.end(); ++iter) { |
|---|
| 123 | lua_pushnumber(d_lua, iter->second); |
|---|
| 124 | lua_setfield(d_lua, -2, iter->first.c_str()); |
|---|
| 125 | } |
|---|
| 126 | lua_pushnumber(d_lua, 3); |
|---|
| 127 | lua_setfield(d_lua, -2, "NXDOMAIN"); |
|---|
| 128 | lua_setglobal(d_lua, "pdns"); |
|---|
| 129 | } |
|---|
| 130 | |
|---|
| 131 | bool PowerDNSLua::nxdomain(const ComboAddress& remote, const ComboAddress& local,const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res) |
|---|
| 132 | { |
|---|
| 133 | return passthrough("nxdomain", remote, local, query, qtype, ret, res); |
|---|
| 134 | } |
|---|
| 135 | |
|---|
| 136 | bool PowerDNSLua::preresolve(const ComboAddress& remote, const ComboAddress& local,const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res) |
|---|
| 137 | { |
|---|
| 138 | return passthrough("preresolve", remote, local, query, qtype, ret, res); |
|---|
| 139 | } |
|---|
| 140 | |
|---|
| 141 | bool PowerDNSLua::getFromTable(const std::string& key, std::string& value) |
|---|
| 142 | { |
|---|
| 143 | lua_pushstring(d_lua, key.c_str()); // 4 is now '1' |
|---|
| 144 | lua_gettable(d_lua, -2); // replace by the first entry of our table we hope |
|---|
| 145 | |
|---|
| 146 | bool ret=false; |
|---|
| 147 | if(!lua_isnil(d_lua, -1)) { |
|---|
| 148 | value = lua_tostring(d_lua, -1); |
|---|
| 149 | ret=true; |
|---|
| 150 | } |
|---|
| 151 | lua_pop(d_lua, 1); |
|---|
| 152 | return ret; |
|---|
| 153 | } |
|---|
| 154 | |
|---|
| 155 | |
|---|
| 156 | bool PowerDNSLua::getFromTable(const std::string& key, uint32_t& 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 = (uint32_t)lua_tonumber(d_lua, -1); |
|---|
| 164 | ret=true; |
|---|
| 165 | } |
|---|
| 166 | lua_pop(d_lua, 1); |
|---|
| 167 | return ret; |
|---|
| 168 | } |
|---|
| 169 | |
|---|
| 170 | |
|---|
| 171 | bool PowerDNSLua::passthrough(const string& func, const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res) |
|---|
| 172 | { |
|---|
| 173 | lua_getglobal(d_lua, func.c_str()); |
|---|
| 174 | if(!lua_isfunction(d_lua, -1)) { |
|---|
| 175 | // cerr<<"No such function '"<<func<<"'\n"; |
|---|
| 176 | lua_pop(d_lua, 1); |
|---|
| 177 | return false; |
|---|
| 178 | } |
|---|
| 179 | /* the first argument */ |
|---|
| 180 | lua_pushstring(d_lua, remote.toString().c_str() ); |
|---|
| 181 | lua_pushstring(d_lua, local.toString().c_str() ); |
|---|
| 182 | lua_pushstring(d_lua, query.c_str() ); |
|---|
| 183 | lua_pushnumber(d_lua, qtype.getCode() ); |
|---|
| 184 | |
|---|
| 185 | if(lua_pcall(d_lua, 4, 2, 0)) { // error |
|---|
| 186 | string error=string("lua error in '"+func+"': ")+lua_tostring(d_lua, -1); |
|---|
| 187 | lua_pop(d_lua, 1); |
|---|
| 188 | throw runtime_error(error); |
|---|
| 189 | return false; |
|---|
| 190 | } |
|---|
| 191 | int newres = (int)lua_tonumber(d_lua, 1); // new rcode |
|---|
| 192 | if(newres < 0) { |
|---|
| 193 | // cerr << "handler did not handle"<<endl; |
|---|
| 194 | lua_pop(d_lua, 2); |
|---|
| 195 | return false; |
|---|
| 196 | } |
|---|
| 197 | res=newres; |
|---|
| 198 | |
|---|
| 199 | /* get the result */ |
|---|
| 200 | DNSResourceRecord rr; |
|---|
| 201 | rr.qname = query; |
|---|
| 202 | rr.d_place = DNSResourceRecord::ANSWER; |
|---|
| 203 | rr.ttl = 3600; |
|---|
| 204 | |
|---|
| 205 | ret.clear(); |
|---|
| 206 | |
|---|
| 207 | /* 1 2 3 4 */ |
|---|
| 208 | /* stack: boolean table key row */ |
|---|
| 209 | |
|---|
| 210 | #ifndef LUA_VERSION_NUM |
|---|
| 211 | int tableLen = luaL_getn(d_lua, 2); |
|---|
| 212 | #else |
|---|
| 213 | int tableLen = lua_objlen(d_lua, 2); |
|---|
| 214 | #endif |
|---|
| 215 | |
|---|
| 216 | for(int n=1; n < tableLen + 1; ++n) { |
|---|
| 217 | lua_pushnumber(d_lua, n); |
|---|
| 218 | lua_gettable(d_lua, 2); |
|---|
| 219 | |
|---|
| 220 | uint32_t tmpnum; |
|---|
| 221 | if(!getFromTable("qtype", tmpnum)) |
|---|
| 222 | rr.qtype=QType::A; |
|---|
| 223 | else |
|---|
| 224 | rr.qtype=tmpnum; |
|---|
| 225 | |
|---|
| 226 | getFromTable("content", rr.content); |
|---|
| 227 | if(!getFromTable("ttl", rr.ttl)) |
|---|
| 228 | rr.ttl=3600; |
|---|
| 229 | |
|---|
| 230 | if(!getFromTable("qname", rr.qname)) |
|---|
| 231 | rr.qname = query; |
|---|
| 232 | |
|---|
| 233 | if(!getFromTable("place", tmpnum)) |
|---|
| 234 | rr.d_place = DNSResourceRecord::ANSWER; |
|---|
| 235 | else |
|---|
| 236 | rr.d_place = (DNSResourceRecord::Place) tmpnum; |
|---|
| 237 | |
|---|
| 238 | /* removes 'value'; keeps 'key' for next iteration */ |
|---|
| 239 | lua_pop(d_lua, 1); // table |
|---|
| 240 | |
|---|
| 241 | // cerr<<"Adding content '"<<rr.content<<"' with place "<<(int)rr.d_place<<" \n"; |
|---|
| 242 | ret.push_back(rr); |
|---|
| 243 | } |
|---|
| 244 | |
|---|
| 245 | lua_pop(d_lua, 2); |
|---|
| 246 | |
|---|
| 247 | return true; |
|---|
| 248 | } |
|---|
| 249 | |
|---|
| 250 | PowerDNSLua::~PowerDNSLua() |
|---|
| 251 | { |
|---|
| 252 | lua_close(d_lua); |
|---|
| 253 | } |
|---|
| 254 | #endif |
|---|