]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/lua-pdns.cc
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "lua-pdns.hh"
26 // #include "syncres.hh"
29 #if !defined(HAVE_LUA)
31 // stub implementation
33 PowerDNSLua::PowerDNSLua(const std::string
& fname
)
35 throw runtime_error("Lua support disabled");
39 PowerDNSLua::~PowerDNSLua()
48 /* Include the Lua API header files. */
60 #include "namespaces.hh"
61 #include "dnsparser.hh"
64 bool netmaskMatchTable(lua_State
* lua
, const std::string
& ip
)
66 lua_pushnil(lua
); /* first key */
67 while (lua_next(lua
, 2) != 0) {
68 string netmask
=lua_tostring(lua
, -1);
79 static bool getFromTable(lua_State
*lua
, const std::string
&key
, std::string
& value
)
81 lua_pushstring(lua
, key
.c_str()); // 4 is now '1'
82 lua_gettable(lua
, -2); // replace by the first entry of our table we hope
85 if(!lua_isnil(lua
, -1)) {
86 value
= lua_tostring(lua
, -1);
93 static bool getFromTable(lua_State
*lua
, const std::string
&key
, uint32_t& value
)
95 lua_pushstring(lua
, key
.c_str()); // 4 is now '1'
96 lua_gettable(lua
, -2); // replace by the first entry of our table we hope
100 if(!lua_isnil(lua
, -1)) {
101 value
= (uint32_t)lua_tonumber(lua
, -1);
109 void pushLuaTable(lua_State
* lua
, const vector
<pair
<string
,string
>>& table
)
112 for(const auto& e
: table
) {
113 lua_pushstring(lua
, e
.second
.c_str());
114 lua_setfield(lua
, -2, e
.first
.c_str());
118 vector
<pair
<string
,string
>> getLuaTable(lua_State
* lua
, int index
)
120 vector
<pair
<string
,string
>> ret
;
121 // Push another reference to the table on top of the stack (so we know
122 // where it is, and this function can work for negative, positive and
124 lua_pushvalue(lua
, index
);
125 // stack now contains: -1 => table
127 // stack now contains: -1 => nil; -2 => table
128 while (lua_next(lua
, -2)) {
129 // stack now contains: -1 => value; -2 => key; -3 => table
130 // copy the key so that lua_tostring does not modify the original
131 lua_pushvalue(lua
, -2);
132 // stack now contains: -1 => key; -2 => value; -3 => key; -4 => table
133 const char *key
= lua_tostring(lua
, -1);
134 const char *value
= lua_tostring(lua
, -2);
135 ret
.push_back({key
,value
});
136 // pop value + copy of key, leaving original key
138 // stack now contains: -1 => key; -2 => table
140 // stack now contains: -1 => table (when lua_next returns 0 it pops the key
141 // but does not push anything.)
144 // Stack is now the same as it was on entry to this function
149 void pushResourceRecordsTable(lua_State
* lua
, const vector
<DNSRecord
>& records
)
151 // make a table of tables
155 for(const auto& rr
: records
)
157 // row number, used by 'lua_settable' below
158 lua_pushnumber(lua
, ++pos
);
162 lua_pushstring(lua
, rr
.d_name
.toString().c_str());
163 lua_setfield(lua
, -2, "qname"); // pushes value at the top of the stack to the table immediately below that (-1 = top, -2 is below)
165 lua_pushstring(lua
, rr
.d_content
->getZoneRepresentation().c_str());
166 lua_setfield(lua
, -2, "content");
168 lua_pushnumber(lua
, rr
.d_type
);
169 lua_setfield(lua
, -2, "qtype");
171 lua_pushnumber(lua
, rr
.d_ttl
);
172 lua_setfield(lua
, -2, "ttl");
174 lua_pushnumber(lua
, rr
.d_place
);
175 lua_setfield(lua
, -2, "place");
177 lua_pushnumber(lua
, rr
.d_class
);
178 lua_setfield(lua
, -2, "qclass");
180 lua_settable(lua
, -3); // pushes the table we just built into the master table at position pushed above
183 // override the __index metatable under loglevels to return Logger::Error to account for nil accesses to the loglevels table
184 int loglevels_index(lua_State
* lua
)
186 lua_pushnumber(lua
, Logger::Error
);
189 // push the loglevel subtable onto the stack that will eventually be the pdns table
190 void pushSyslogSecurityLevelTable(lua_State
* lua
)
193 // this function takes the global lua_state from the PowerDNSLua constructor and populates it with the syslog enums values
194 lua_pushnumber(lua
, Logger::All
);
195 lua_setfield(lua
, -2, "All");
196 lua_pushnumber(lua
, Logger::Alert
);
197 lua_setfield(lua
, -2, "Alert");
198 lua_pushnumber(lua
, Logger::Critical
);
199 lua_setfield(lua
, -2, "Critical");
200 lua_pushnumber(lua
, Logger::Error
);
201 lua_setfield(lua
, -2, "Error");
202 lua_pushnumber(lua
, Logger::Warning
);
203 lua_setfield(lua
, -2, "Warning");
204 lua_pushnumber(lua
, Logger::Notice
);
205 lua_setfield(lua
, -2, "Notice");
206 lua_pushnumber(lua
, Logger::Info
);
207 lua_setfield(lua
, -2, "Info");
208 lua_pushnumber(lua
, Logger::Debug
);
209 lua_setfield(lua
, -2, "Debug");
210 lua_pushnumber(lua
, Logger::None
);
211 lua_setfield(lua
, -2, "None");
212 lua_createtable(lua
, 0, 1);
213 lua_pushcfunction(lua
, loglevels_index
);
214 lua_setfield(lua
, -2, "__index");
215 lua_setmetatable(lua
, -2);
217 int getLuaTableLength(lua_State
* lua
, int depth
)
219 #ifndef LUA_VERSION_NUM
220 return luaL_getn(lua
, 2);
221 #elif LUA_VERSION_NUM < 502
222 return lua_objlen(lua
, 2);
224 return lua_rawlen(lua
, 2);
228 // expects a table at offset 2, and, importantly DOES NOT POP IT from the stack - only the contents
229 void popResourceRecordsTable(lua_State
*lua
, const DNSName
&query
, vector
<DNSRecord
>& ret
)
234 rr
.d_place
= DNSResourceRecord::ANSWER
;
237 int tableLen
= getLuaTableLength(lua
, 2);
239 for(int n
=1; n
< tableLen
+ 1; ++n
) {
240 lua_pushnumber(lua
, n
);
241 lua_gettable(lua
, 2);
244 if(!getFromTable(lua
, "qtype", tmpnum
))
249 if(!getFromTable(lua
, "qclass", tmpnum
))
250 rr
.d_class
= QClass::IN
;
257 getFromTable(lua
, "content", content
);
258 rr
.d_content
=DNSRecordContent::mastermake(rr
.d_type
, rr
.d_class
, content
);
260 if(!getFromTable(lua
, "ttl", rr
.d_ttl
))
264 if(getFromTable(lua
, "qname", qname
))
265 rr
.d_name
= DNSName(qname
);
269 if(!getFromTable(lua
, "place", tmpnum
))
270 rr
.d_place
= DNSResourceRecord::ANSWER
;
272 rr
.d_place
= static_cast<DNSResourceRecord::Place
>(tmpnum
);
273 if(rr
.d_place
> DNSResourceRecord::ADDITIONAL
)
274 rr
.d_place
= DNSResourceRecord::ADDITIONAL
;
278 /* removes 'value'; keeps 'key' for next iteration */
279 lua_pop(lua
, 1); // table
281 // cerr<<"Adding content '"<<rr.content<<"' with place "<<(int)rr.d_place<<" \n";
288 int netmaskMatchLua(lua_State
*lua
)
291 if(lua_gettop(lua
) >= 2) {
292 string ip
=lua_tostring(lua
, 1);
293 if(lua_istable(lua
, 2)) {
294 result
= netmaskMatchTable(lua
, ip
);
297 for(int n
=2 ; n
<= lua_gettop(lua
); ++n
) {
298 string netmask
=lua_tostring(lua
, n
);
302 result
= nm
.match(ip
);
309 lua_pushboolean(lua
, result
);
313 int getLocalAddressLua(lua_State
* lua
)
315 lua_getfield(lua
, LUA_REGISTRYINDEX
, "__PowerDNSLua");
316 PowerDNSLua
* pl
= (PowerDNSLua
*)lua_touserdata(lua
, -1);
318 lua_pushstring(lua
, pl
->getLocal().toString().c_str());
322 // called by lua to indicate that this answer is 'variable' and should not be cached
323 int setVariableLua(lua_State
* lua
)
325 lua_getfield(lua
, LUA_REGISTRYINDEX
, "__PowerDNSLua");
326 PowerDNSLua
* pl
= (PowerDNSLua
*)lua_touserdata(lua
, -1);
331 int logLua(lua_State
*lua
)
333 // get # of arguments from the pdnslog() lua stack
334 // if it is 1, then the old pdnslog(msg) is used, which we keep for posterity and to prevent lua scripts from breaking
335 // if it is >= 2, then we process it as pdnslog(msg, urgencylevel) for more granular logging
336 int argc
= lua_gettop(lua
);
338 string message
=lua_tostring(lua
, 1);
339 theL()<<Logger::Error
<<"From Lua script: "<<message
<<endl
;
340 } else if(argc
>= 2) {
341 string message
=lua_tostring(lua
, 1);
342 int urgencylevel
= lua_tonumber(lua
, 2);
343 theL()<<urgencylevel
<<" "<<message
<<endl
;
349 PowerDNSLua::PowerDNSLua(const std::string
& fname
)
351 d_lua
= luaL_newstate();
353 // create module iputils & load it
354 #if LUA_VERSION_NUM < 502
355 luaopen_iputils(d_lua
);
357 luaL_requiref(d_lua
, "iputils", luaopen_iputils
, 1);
360 lua_pushcfunction(d_lua
, netmaskMatchLua
);
361 lua_setglobal(d_lua
, "matchnetmask");
363 lua_pushcfunction(d_lua
, logLua
);
364 lua_setglobal(d_lua
, "pdnslog");
368 for(vector
<QType::namenum
>::const_iterator iter
= QType::names
.begin(); iter
!= QType::names
.end(); ++iter
) {
369 lua_pushnumber(d_lua
, iter
->second
);
370 lua_setfield(d_lua
, -2, iter
->first
.c_str());
372 lua_pushnumber(d_lua
, 0);
373 lua_setfield(d_lua
, -2, "NOERROR");
374 lua_pushnumber(d_lua
, 1);
375 lua_setfield(d_lua
, -2, "FORMERR");
376 lua_pushnumber(d_lua
, 2);
377 lua_setfield(d_lua
, -2, "SERVFAIL");
378 lua_pushnumber(d_lua
, 3);
379 lua_setfield(d_lua
, -2, "NXDOMAIN");
380 lua_pushnumber(d_lua
, 4);
381 lua_setfield(d_lua
, -2, "NOTIMP");
382 lua_pushnumber(d_lua
, 5);
383 lua_setfield(d_lua
, -2, "REFUSED");
384 // set syslog codes used by Logger/enum Urgency
385 pushSyslogSecurityLevelTable(d_lua
);
386 lua_setfield(d_lua
, -2, "loglevels");
387 lua_pushnumber(d_lua
, PolicyDecision::PASS
);
388 lua_setfield(d_lua
, -2, "PASS");
389 lua_pushnumber(d_lua
, PolicyDecision::DROP
);
390 lua_setfield(d_lua
, -2, "DROP");
391 lua_pushnumber(d_lua
, PolicyDecision::TRUNCATE
);
392 lua_setfield(d_lua
, -2, "TRUNCATE");
394 lua_setglobal(d_lua
, "pdns");
396 #ifndef LUA_VERSION_NUM
398 luaopen_string(d_lua
);
400 if(lua_dofile(d_lua
, fname
.c_str()))
402 luaL_openlibs(d_lua
);
403 if(luaL_dofile(d_lua
, fname
.c_str()))
405 throw runtime_error(string("Error loading Lua file '")+fname
+"': "+ string(lua_isstring(d_lua
, -1) ? lua_tostring(d_lua
, -1) : "unknown error"));
407 lua_settop(d_lua
, 0);
409 lua_pushcfunction(d_lua
, setVariableLua
);
410 lua_setglobal(d_lua
, "setvariable");
412 lua_pushcfunction(d_lua
, getLocalAddressLua
);
413 lua_setglobal(d_lua
, "getlocaladdress");
415 lua_pushlightuserdata(d_lua
, (void*)this);
416 lua_setfield(d_lua
, LUA_REGISTRYINDEX
, "__PowerDNSLua");
419 bool PowerDNSLua::getFromTable(const std::string
& key
, std::string
& value
)
421 return ::getFromTable(d_lua
, key
, value
);
424 bool PowerDNSLua::getFromTable(const std::string
& key
, uint32_t& value
)
426 return ::getFromTable(d_lua
, key
, value
);
429 PowerDNSLua::~PowerDNSLua()
435 void luaStackDump (lua_State
*Lua
) {
437 int top
= lua_gettop(Lua
);
438 for (i
= 1; i
<= top
; i
++) { /* repeat for each level */
439 int t
= lua_type(Lua
, i
);
442 case LUA_TSTRING
: /* strings */
443 printf("`%s'", lua_tostring(Lua
, i
));
446 case LUA_TBOOLEAN
: /* booleans */
447 printf(lua_toboolean(Lua
, i
) ? "true" : "false");
450 case LUA_TNUMBER
: /* numbers */
451 printf("%g", lua_tonumber(Lua
, i
));
454 default: /* other values */
455 printf("%s", lua_typename(Lua
, t
));
459 printf(" "); /* put a separator */
461 printf("\n"); /* end the listing */