From: Victor Julien Date: Thu, 11 Apr 2024 14:10:34 +0000 (+0200) Subject: detect/lua: add support for datasets X-Git-Tag: suricata-8.0.0-beta1~575 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ccebae6ec0fad570412ada758981e5f2b14c15e4;p=thirdparty%2Fsuricata.git detect/lua: add support for datasets dataset.new create a dataset object in lua :get gets a reference to an existing dataset :add returns 1 if a new entry was added returns 0 if entry was already in the set Example: ``` function init (args) local needs = {} needs["packet"] = tostring(true) return needs end function thread_init (args) conn_new, dataset.new() ret, err conn_new:get("conn-seen") if err ~= nil then SCLogWarning("dataset warning: " .. err) return 0 end end function match (args) ipver, srcip, dstip, proto, sp, dp = SCFlowTuple() str = ipver .. ":<" .. srcip .. ">:<" .. dstip .. ">:" .. dp ret, err = conn_new:add(str, #str); if ret == 1 then SCLogInfo(str .. " => " .. ret) end return ret end ``` Ticket: #7243. --- diff --git a/src/detect-lua-extensions.c b/src/detect-lua-extensions.c index aa2d7a3ae6..9b74d0f864 100644 --- a/src/detect-lua-extensions.c +++ b/src/detect-lua-extensions.c @@ -28,6 +28,7 @@ #include "threads.h" #include "decode.h" +#include "datasets.h" #include "detect.h" #include "detect-parse.h" @@ -414,6 +415,121 @@ static int LuaSetFlowint(lua_State *luastate) return 0; } +struct LuaDataset { + Dataset *set; +}; + +static int LuaDatasetGC(lua_State *luastate) +{ + SCLogDebug("gc:start"); + struct LuaDataset *s = (struct LuaDataset *)lua_touserdata(luastate, 1); + SCLogDebug("deref %s", s->set->name); + s->set = NULL; + SCLogDebug("gc:done"); + return 0; +} + +static int LuaDatasetGetRef(lua_State *luastate) +{ + SCLogDebug("get"); + struct LuaDataset *s = (struct LuaDataset *)lua_touserdata(luastate, 1); + if (s == NULL) { + LUA_ERROR("dataset is not initialized"); + } + + const char *name = lua_tostring(luastate, 2); + if (name == NULL) { + LUA_ERROR("null string"); + } + + Dataset *dataset = DatasetFind(name, DATASET_TYPE_STRING); + if (dataset == NULL) { + LUA_ERROR("dataset not found"); + } + s->set = dataset; + return 0; +} + +static int LuaDatasetAdd(lua_State *luastate) +{ + SCLogDebug("add:start"); + struct LuaDataset *s = (struct LuaDataset *)lua_touserdata(luastate, 1); + if (s == NULL) { + LUA_ERROR("dataset is not initialized"); + } + if (!lua_isstring(luastate, 2)) { + LUA_ERROR("1st arg is not a string"); + } + if (!lua_isnumber(luastate, 3)) { + LUA_ERROR("2nd arg is not a number"); + } + + const uint8_t *str = (const uint8_t *)lua_tostring(luastate, 2); + if (str == NULL) { + LUA_ERROR("1st arg is not null string"); + } + + uint32_t str_len = lua_tonumber(luastate, 3); + + int r = DatasetAdd(s->set, (const uint8_t *)str, str_len); + /* return value through luastate, as a luanumber */ + lua_pushnumber(luastate, (lua_Number)r); + SCLogDebug("add:end"); + return 1; +} + +static int LuaDatasetNew(lua_State *luastate) +{ + SCLogDebug("new:start"); + struct LuaDataset *s = (struct LuaDataset *)lua_newuserdata(luastate, sizeof(*s)); + if (s == NULL) { + LUA_ERROR("failed to get userdata"); + } + luaL_getmetatable(luastate, "dataset::metatable"); + lua_setmetatable(luastate, -2); + SCLogDebug("new:done"); + return 1; +} + +// clang-format off +const luaL_Reg datasetlib[] = { + { "new", LuaDatasetNew }, + { "get", LuaDatasetGetRef }, + { "add", LuaDatasetAdd }, + { "__gc", LuaDatasetGC }, + { NULL, NULL } +}; +// clang-format on + +static void SetFuncs(lua_State *luastate, const luaL_Reg *lib) +{ + for (; lib->name != NULL; lib++) { + lua_pushstring(luastate, lib->name); + lua_pushcfunction(luastate, lib->func); + lua_settable(luastate, -3); + } +} + +static void CreateMeta(lua_State *luastate) +{ + luaL_newmetatable(luastate, "dataset::metatable"); + lua_pushliteral(luastate, "__index"); + lua_pushvalue(luastate, -2); + lua_rawset(luastate, -3); + SetFuncs(luastate, datasetlib); +} + +static void LuaDatasetRegister(lua_State *luastate) +{ + CreateMeta(luastate); + lua_newtable(luastate); + SetFuncs(luastate, datasetlib); + lua_pushvalue(luastate, -1); + lua_setglobal(luastate, "dataset"); + lua_pop(luastate, 1); + lua_pop(luastate, 1); +} + static int LuaIncrFlowint(lua_State *luastate) { uint32_t idx; @@ -578,6 +694,8 @@ int LuaRegisterExtensions(lua_State *lua_state) lua_pushcfunction(lua_state, LuaGetByteVar); lua_setglobal(lua_state, "SCByteVarGet"); + LuaDatasetRegister(lua_state); + LuaRegisterFunctions(lua_state); LuaRegisterHttpFunctions(lua_state); LuaRegisterDnsFunctions(lua_state);