From b0ed8f1a4046c3e3c3be69aa20fdfb5a2e477dcc Mon Sep 17 00:00:00 2001 From: bert hubert Date: Mon, 5 Jan 2015 13:24:55 +0100 Subject: [PATCH] expose 'iputils' module to Lua code, allowing for native IP(v6) address processing, netmasks and netmaskgroups --- pdns/Makefile.am | 8 +- pdns/lua-iputils.cc | 345 +++++++++++++++++++++++++++++++++++++++++++ pdns/lua-pdns.cc | 7 + pdns/lua-pdns.hh | 1 + pdns/lua-recursor.cc | 10 +- 5 files changed, 368 insertions(+), 3 deletions(-) create mode 100644 pdns/lua-iputils.cc diff --git a/pdns/Makefile.am b/pdns/Makefile.am index eef73aa928..5464997864 100644 --- a/pdns/Makefile.am +++ b/pdns/Makefile.am @@ -137,7 +137,7 @@ pdns_server_SOURCES = \ lock.hh \ logger.cc logger.hh \ lua-auth.cc lua-auth.hh \ - lua-pdns.cc \ + lua-pdns.cc lua-iputils.cc \ mastercommunicator.cc \ md5.hh \ misc.cc misc.hh \ @@ -360,6 +360,10 @@ zone2json_SOURCES = \ zone2json_LDFLAGS = $(THREADFLAGS) zone2json_LDADD = $(POLARSSL_LIBS) +# pkglib_LTLIBRARIES = iputils.la +# iputils_la_SOURCES = lua-iputils.cc +# iputils_la_LDFLAGS= -module -avoid-version + zone2ldap_SOURCES = \ arguments.cc \ base32.cc \ @@ -885,7 +889,7 @@ pdns_recursor_SOURCES = \ htimer.cc htimer.hh \ json.cc json.hh \ logger.cc \ - lua-pdns.cc lua-pdns.hh \ + lua-pdns.cc lua-pdns.hh lua-iputils.cc \ lua-recursor.cc lua-recursor.hh \ lwres.cc lwres.hh \ misc.cc \ diff --git a/pdns/lua-iputils.cc b/pdns/lua-iputils.cc new file mode 100644 index 0000000000..89b8f15545 --- /dev/null +++ b/pdns/lua-iputils.cc @@ -0,0 +1,345 @@ +extern "C" { +#include +#include +} +#include +#include "iputils.hh" +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +#undef L + +#if !defined LUA_VERSION_NUM || LUA_VERSION_NUM==501 +/* +** Adapted from Lua 5.2.0 +*/ +static void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { + luaL_checkstack(L, nup+1, "too many upvalues"); + for (; l->name != NULL; l++) { /* fill the table with given functions */ + int i; + lua_pushstring(L, l->name); + for (i = 0; i < nup; i++) /* copy upvalues to the top */ + lua_pushvalue(L, -(nup+1)); + lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ + lua_settable(L, -(nup + 3)); + } + lua_pop(L, nup); /* remove upvalues */ +} +#endif + + +///////////////////////////////// + +static int l_new_ca(lua_State* L) +{ + ComboAddress* ca=(ComboAddress*)lua_newuserdata(L, sizeof(ComboAddress)); + memset(ca, 0, sizeof(ComboAddress)); + *ca=ComboAddress(luaL_checkstring(L, 1)); + luaL_getmetatable(L, "iputils.ca"); + lua_setmetatable(L, -2); + return 1; +} + +static int l_ca_tostring(lua_State* L) +{ + ComboAddress* ca = (ComboAddress*)luaL_checkudata(L, 1, "iputils.ca"); + + string ret=ca->toString(); + lua_pushstring(L, ret.c_str()); + return 1; +} + +static int l_ca_tostringWithPort(lua_State* L) +{ + ComboAddress* ca = (ComboAddress*)luaL_checkudata(L, 1, "iputils.ca"); + + string ret=ca->toStringWithPort(); + lua_pushstring(L, ret.c_str()); + return 1; +} + +static int l_ca_equal(lua_State* L) +{ + ComboAddress* ca1 = (ComboAddress*)luaL_checkudata(L, 1, "iputils.ca"); + ComboAddress* ca2 = (ComboAddress*)luaL_checkudata(L, 2, "iputils.ca"); + lua_pushboolean(L, *ca1==*ca2); + return 1; +} + +static const struct luaL_Reg iputils_ca_methods[]={ + {"tostring", l_ca_tostring}, + {"__tostring", l_ca_tostring}, + {"__eq", l_ca_equal}, + {"tostringwithport", l_ca_tostringWithPort}, + {NULL, NULL} +}; + + +///////////////////////////// + +static int l_ipset_index(lua_State* L) +{ + set*ourset = (set*)luaL_checkudata(L, 1, "iputils.ipset"); + ComboAddress* ca1 = (ComboAddress*)luaL_checkudata(L, 2, "iputils.ca"); + if(ourset->count(*ca1)) { + lua_pushboolean(L, 1); + return 1; + } + + return 0; +} + +static int l_ipset_newindex(lua_State* L) +{ + set*ourset = (set*)luaL_checkudata(L, 1, "iputils.ipset"); + ComboAddress* ca1 = (ComboAddress*)luaL_checkudata(L, 2, "iputils.ca"); + ourset->insert(*ca1); + return 0; +} + +static int l_newipset(lua_State* L) +{ + new(lua_newuserdata(L, sizeof(set))) set(); + luaL_getmetatable(L, "iputils.ipset"); + lua_setmetatable(L, -2); + return 1; +} + +static int l_ipset_gc(lua_State* L) +{ + set*ourset = (set*)luaL_checkudata(L, 1, "iputils.ipset"); + ourset->~set(); + return 0; +} + +static const struct luaL_Reg ipset_methods[]={ + {"__index", l_ipset_index}, + {"__newindex", l_ipset_newindex}, + {"__gc", l_ipset_gc}, + {NULL, NULL} +}; + +//////////////////////////////////////////////////// + + +static int l_netmask_tostring(lua_State* L) +{ + Netmask* nm = (Netmask*)luaL_checkudata(L, 1, "iputils.netmask"); + string ret=nm->toString(); + lua_pushstring(L, ret.c_str()); + return 1; +} + +static int l_new_netmask(lua_State* L) +{ + /*Netmask* nm=*/ new(lua_newuserdata(L, sizeof(Netmask))) Netmask(luaL_checkstring(L, 1)); + luaL_getmetatable(L, "iputils.netmask"); + lua_setmetatable(L, -2); + return 1; +} + +static int l_netmask_match(lua_State* L) +{ + Netmask* nm=(Netmask*)luaL_checkudata(L, 1, "iputils.netmask"); + ComboAddress* ca1 = (ComboAddress*)luaL_checkudata(L, 2, "iputils.ca"); + lua_pushboolean(L, nm->match(*ca1)); + return 1; +} + +static int l_netmask_gc(lua_State* L) +{ + Netmask* nm = (Netmask*)luaL_checkudata(L, 1, "iputils.netmask"); + nm->~Netmask(); + return 0; +} + +static const struct luaL_Reg iputils_netmask_methods[]={ + {"__tostring", l_netmask_tostring}, + {"match", l_netmask_match}, + {"__gc", l_netmask_gc}, + {NULL, NULL} +}; + + +////////////////////// + +static int l_nmgroup_tostring(lua_State* L) +{ + NetmaskGroup* nmg = (NetmaskGroup*)luaL_checkudata(L, 1, "iputils.nmgroup"); + + string ret=nmg->toString(); + lua_pushstring(L, ret.c_str()); + return 1; +} + +static int l_new_nmgroup(lua_State* L) +{ + /*NetmaskGroup*nmg= */ new(lua_newuserdata(L, sizeof(NetmaskGroup))) NetmaskGroup(); + luaL_getmetatable(L, "iputils.nmgroup"); + lua_setmetatable(L, -2); + return 1; +} + +static int l_nmgroup_match(lua_State* L) +{ + NetmaskGroup* nm=(NetmaskGroup*)luaL_checkudata(L, 1, "iputils.nmgroup"); + ComboAddress* ca1 = (ComboAddress*)luaL_checkudata(L, 2, "iputils.ca"); + lua_pushboolean(L, nm->match(*ca1)); + return 1; +} + +static int l_nmgroup_add(lua_State* L) +{ + NetmaskGroup* nm=(NetmaskGroup*)luaL_checkudata(L, 1, "iputils.nmgroup"); + nm->addMask(luaL_checkstring(L, 2)); + return 0; +} + + +static int l_nmgroup_gc(lua_State* L) +{ + NetmaskGroup* nm = (NetmaskGroup*)luaL_checkudata(L, 1, "iputils.nmgroup"); + nm->~NetmaskGroup(); + return 0; +} + +static const struct luaL_Reg iputils_nmgroup_methods[]={ + {"__tostring", l_nmgroup_tostring}, + {"match", l_nmgroup_match}, + {"add", l_nmgroup_add}, + {"__gc", l_nmgroup_gc}, + {NULL, NULL} +}; + +//////////// + +static const struct luaL_Reg iputils[]={ + {"newca", l_new_ca}, + {"newipset", l_newipset}, + {"newnm", l_new_netmask}, + {"newnmgroup", l_new_nmgroup}, + {NULL, NULL} +}; + + +extern "C" int luaopen_iputils(lua_State* L) +{ + luaL_newmetatable(L, "iputils.ca"); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + luaL_setfuncs(L, iputils_ca_methods, 0); + + luaL_newmetatable(L, "iputils.ipset"); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + luaL_setfuncs(L, ipset_methods, 0); + + luaL_newmetatable(L, "iputils.netmask"); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + luaL_setfuncs(L, iputils_netmask_methods, 0); + + luaL_newmetatable(L, "iputils.nmgroup"); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + luaL_setfuncs(L, iputils_nmgroup_methods, 0); + +#if LUA_VERSION_NUM < 502 + luaL_register(L, "iputils", iputils); +#else + luaL_newlib(L, iputils); +#endif + return 1; +} + +#if 0 +int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret) +{ + if(addr.empty()) + return -1; + string ourAddr(addr); + int port = -1; + if(addr[0]=='[') { // [::]:53 style address + string::size_type pos = addr.find(']'); + if(pos == string::npos || pos + 2 > addr.size() || addr[pos+1]!=':') + return -1; + ourAddr.assign(addr.c_str() + 1, pos-1); + port = atoi(addr.c_str()+pos+2); + } + ret->sin6_scope_id=0; + ret->sin6_family=AF_INET6; + if(inet_pton(AF_INET6, ourAddr.c_str(), (void*)&ret->sin6_addr) != 1) { + struct addrinfo* res; + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = AF_INET6; + hints.ai_flags = AI_NUMERICHOST; + + int error; + if((error=getaddrinfo(ourAddr.c_str(), 0, &hints, &res))) { // this is correct + return -1; + } + + memcpy(ret, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + } + + if(port >= 0) + ret->sin6_port = htons(port); + + return 0; +} + +int makeIPv4sockaddr(const std::string& str, struct sockaddr_in* ret) +{ + if(str.empty()) { + return -1; + } + struct in_addr inp; + + string::size_type pos = str.find(':'); + if(pos == string::npos) { // no port specified, not touching the port + if(inet_aton(str.c_str(), &inp)) { + ret->sin_addr.s_addr=inp.s_addr; + return 0; + } + return -1; + } + if(!*(str.c_str() + pos + 1)) // trailing : + return -1; + + char *eptr = (char*)str.c_str() + str.size(); + int port = strtol(str.c_str() + pos + 1, &eptr, 10); + if(*eptr) + return -1; + + ret->sin_port = htons(port); + if(inet_aton(str.substr(0, pos).c_str(), &inp)) { + ret->sin_addr.s_addr=inp.s_addr; + return 0; + } + return -1; +} + + +pair splitField(const string& inp, char sepa) +{ + pair ret; + string::size_type cpos=inp.find(sepa); + if(cpos==string::npos) + ret.first=inp; + else { + ret.first=inp.substr(0, cpos); + ret.second=inp.substr(cpos+1); + } + return ret; +} + +#endif diff --git a/pdns/lua-pdns.cc b/pdns/lua-pdns.cc index 25e9348b8b..4dbde69c2a 100644 --- a/pdns/lua-pdns.cc +++ b/pdns/lua-pdns.cc @@ -278,6 +278,13 @@ PowerDNSLua::PowerDNSLua(const std::string& fname) { d_lua = luaL_newstate(); + // create module iputils & load it +#if LUA_VERSION_NUM < 502 + luaopen_iputils(d_lua); +#else + luaL_requiref(d_lua, "iputils", luaopen_iputils, 1); +#endif + lua_pushcfunction(d_lua, netmaskMatchLua); lua_setglobal(d_lua, "matchnetmask"); diff --git a/pdns/lua-pdns.hh b/pdns/lua-pdns.hh index 934d02aacb..bdc0ed42cc 100644 --- a/pdns/lua-pdns.hh +++ b/pdns/lua-pdns.hh @@ -37,4 +37,5 @@ void popResourceRecordsTable(lua_State *lua, const string &query, vector