lua: convert lua flowint functions to lib: suricata.flowintlib

Ticket: #7487
This commit is contained in:
Jason Ish
2025-05-02 09:32:23 -06:00
parent 12e149b99b
commit 8a5bc12156
8 changed files with 342 additions and 243 deletions
+59
View File
@@ -0,0 +1,59 @@
Flowint Library
###############
The ``suricata.flowint`` library exposes ``flowint`` variables to Lua
scripts.
Initialization
**************
First, the ``flowint`` module must be loaded::
local flowintlib = require("suricata.flowint")
Then in the ``init`` method, any flow integers used in the script
should be registered. This is optional and could be skipped if you
know for sure the flow integers will be registered by some other
means.
Example::
local flowintlib = require("suricata.flowint")
function init ()
flowintlib.register("count")
return {}
end
Finally, in the ``thread_init`` function a handle is acquired for the
flow integers and stored as a global::
function thread_init ()
count_flow_int = flowintlib.get("count")
end
Flow Integer Methods
********************
``decr()``
==========
Decrement the value of the ``flowint`` by 1. The new value is
returned. If the value is 0, it will remain 0.
``incr()``
==========
Increment the value of the ``flowint`` by 1. The new value is
returned.
``value()``
===========
Get the current value of the flow integer. Note that ``nil`` may be
returned if the flow integer does not have a value.
``set(value)``
===================
Set the value of the flowint to the value provided.
+1
View File
@@ -11,6 +11,7 @@ environment without access to additional modules.
base64
dns
flowlib
flowint
flowvar
hashlib
http
+2
View File
@@ -533,6 +533,7 @@ noinst_HEADERS = \
util-lua-dnp3.h \
util-lua-dnp3-objects.h \
util-lua-dns.h \
util-lua-flowintlib.h \
util-lua-flowlib.h \
util-lua-flowvarlib.h \
util-lua.h \
@@ -1102,6 +1103,7 @@ libsuricata_c_a_SOURCES = \
util-lua-dnp3.c \
util-lua-dnp3-objects.c \
util-lua-dns.c \
util-lua-flowintlib.c \
util-lua-flowlib.c \
util-lua-flowvarlib.c \
util-lua-hashlib.c \
-203
View File
@@ -29,7 +29,6 @@
#include "detect.h"
#include "flow.h"
#include "flow-var.h"
#include "util-debug.h"
@@ -39,7 +38,6 @@
#include "util-lua.h"
#include "util-lua-common.h"
#include "util-lua-http.h"
#include "util-lua-ja3.h"
#include "util-lua-tls.h"
#include "util-lua-smtp.h"
@@ -64,183 +62,6 @@ static int GetLuaData(lua_State *luastate, DetectLuaData **ret_ld)
return 0;
}
static int GetFlow(lua_State *luastate, Flow **ret_f)
{
Flow *f = LuaStateGetFlow(luastate);
if (f == NULL) {
LUA_ERROR("no flow");
}
*ret_f = f;
return 0;
}
static int GetFlowIntById(lua_State *luastate, Flow *f,
FlowVar **ret_fv, bool fv_may_be_null, uint32_t *ret_idx)
{
DetectLuaData *ld = NULL;
if (ret_idx)
*ret_idx = 0;
*ret_fv = NULL;
/* need lua data for id -> idx conversion */
int ret = GetLuaData(luastate, &ld);
if (ret != 0)
return ret;
if (!lua_isnumber(luastate, 1)) {
LUA_ERROR("flowvar id not a number");
}
int id = lua_tonumber(luastate, 1);
if (id < 0 || id >= DETECT_LUA_MAX_FLOWVARS) {
LUA_ERROR("flowvar id out of range");
}
uint32_t idx = ld->flowint[id];
if (idx == 0) {
LUA_ERROR("flowvar id uninitialized");
}
FlowVar *fv = FlowVarGet(f, idx);
if (!fv_may_be_null && fv == NULL) {
LUA_ERROR("no flow var");
}
*ret_fv = fv;
if (ret_idx)
*ret_idx = idx;
return 0;
}
static int LuaGetFlowint(lua_State *luastate)
{
Flow *f;
FlowVar *fv;
uint32_t number;
/* need flow */
int ret = GetFlow(luastate, &f);
if (ret != 0)
return ret;
ret = GetFlowIntById(luastate, f, &fv, false, NULL);
if (ret != 0)
return ret;
number = fv->data.fv_int.value;
/* return value through luastate, as a luanumber */
lua_pushnumber(luastate, (lua_Number)number);
return 1;
}
static int LuaSetFlowint(lua_State *luastate)
{
uint32_t idx;
Flow *f;
DetectLuaData *ld;
/* need lua data for id -> idx conversion */
int ret = GetLuaData(luastate, &ld);
if (ret != 0)
return ret;
/* need flow */
ret = GetFlow(luastate, &f);
if (ret != 0)
return ret;
/* need flowint idx */
if (!lua_isnumber(luastate, 1)) {
LUA_ERROR("1st arg not a number");
}
int id = lua_tonumber(luastate, 1);
if (id < 0 || id >= DETECT_LUA_MAX_FLOWVARS) {
LUA_ERROR("flowint id out of range");
}
if (!lua_isnumber(luastate, 2)) {
LUA_ERROR("2nd arg not a number");
}
lua_Number luanumber = lua_tonumber(luastate, 2);
if (luanumber < 0 || id > (double)UINT_MAX) {
LUA_ERROR("value out of range, "
"value must be unsigned 32bit int");
}
uint32_t number = (uint32_t)luanumber;
idx = ld->flowint[id];
if (idx == 0) {
LUA_ERROR("flowint id uninitialized");
}
FlowVarAddInt(f, idx, number);
SCLogDebug("stored flow:%p idx:%u value:%u", f, idx, number);
return 0;
}
static int LuaIncrFlowint(lua_State *luastate)
{
uint32_t idx;
Flow *f;
FlowVar *fv;
uint32_t number;
/* need flow */
int ret = GetFlow(luastate, &f);
if (ret != 0)
return ret;
ret = GetFlowIntById(luastate, f, &fv, true, &idx);
if (ret != 0)
return ret;
if (fv == NULL) {
number = 1;
} else {
number = fv->data.fv_int.value;
if (number < UINT_MAX)
number++;
}
FlowVarAddIntNoLock(f, idx, number);
/* return value through luastate, as a luanumber */
lua_pushnumber(luastate, (lua_Number)number);
SCLogDebug("incremented flow:%p idx:%u value:%u", f, idx, number);
return 1;
}
static int LuaDecrFlowint(lua_State *luastate)
{
uint32_t idx;
Flow *f;
FlowVar *fv;
uint32_t number;
/* need flow */
int ret = GetFlow(luastate, &f);
if (ret != 0)
return ret;
ret = GetFlowIntById(luastate, f, &fv, true, &idx);
if (ret != 0)
return ret;
if (fv == NULL) {
number = 0;
} else {
number = fv->data.fv_int.value;
if (number > 0)
number--;
}
FlowVarAddIntNoLock(f, idx, number);
/* return value through luastate, as a luanumber */
lua_pushnumber(luastate, (lua_Number)number);
SCLogDebug("decremented flow:%p idx:%u value:%u", f, idx, number);
return 1;
}
static int LuaGetByteVar(lua_State *luastate)
{
DetectLuaData *ld = NULL;
@@ -296,30 +117,6 @@ void LuaExtensionsMatchSetup(lua_State *lua_state, DetectLuaData *ld,
*/
int LuaRegisterExtensions(lua_State *lua_state)
{
lua_pushcfunction(lua_state, LuaGetFlowint);
lua_setglobal(lua_state, "ScFlowintGet");
lua_pushcfunction(lua_state, LuaGetFlowint);
lua_setglobal(lua_state, "SCFlowintGet");
lua_pushcfunction(lua_state, LuaSetFlowint);
lua_setglobal(lua_state, "ScFlowintSet");
lua_pushcfunction(lua_state, LuaSetFlowint);
lua_setglobal(lua_state, "SCFlowintSet");
lua_pushcfunction(lua_state, LuaIncrFlowint);
lua_setglobal(lua_state, "ScFlowintIncr");
lua_pushcfunction(lua_state, LuaIncrFlowint);
lua_setglobal(lua_state, "SCFlowintIncr");
lua_pushcfunction(lua_state, LuaDecrFlowint);
lua_setglobal(lua_state, "ScFlowintDecr");
lua_pushcfunction(lua_state, LuaDecrFlowint);
lua_setglobal(lua_state, "SCFlowintDecr");
lua_pushcfunction(lua_state, LuaGetByteVar);
lua_setglobal(lua_state, "SCByteVarGet");
+64 -40
View File
@@ -1505,22 +1505,26 @@ static int LuaMatchTest03a(void)
/** \test http buffer, flowints */
static int LuaMatchTest04(void)
{
const char script[] = "function init (args)\n"
" local needs = {}\n"
" needs[\"flowint\"] = {\"cnt\"}\n"
" return needs\n"
const char script[] = "local flowintlib = require(\"suricata.flowint\")\n"
"function init (args)\n"
" flowintlib.register(\"cnt\")\n"
" return {}\n"
"end\n"
"\n"
"function thread_init (args)\n"
" cnt = flowintlib.get(\"cnt\")\n"
"end\n"
"\n"
"function match(args)\n"
" print \"inspecting\""
" a = ScFlowintGet(0)\n"
" a = cnt:value()\n"
" if a then\n"
" ScFlowintSet(0, a + 1)\n"
" cnt:set(a + 1)\n"
" else\n"
" ScFlowintSet(0, 1)\n"
" cnt:set(1)\n"
" end\n"
" \n"
" a = ScFlowintGet(0)\n"
" a = cnt:value()\n"
" if a == 2 then\n"
" print \"match\"\n"
" return 1\n"
@@ -1621,22 +1625,26 @@ static int LuaMatchTest04(void)
/** \test http buffer, flowints */
static int LuaMatchTest04a(void)
{
const char script[] = "function init (args)\n"
" local needs = {}\n"
" needs[\"flowint\"] = {\"cnt\"}\n"
" return needs\n"
const char script[] = "local flowintlib = require(\"suricata.flowint\")\n"
"function init (args)\n"
" flowintlib.register(\"cnt\")\n"
" return {}\n"
"end\n"
"\n"
"function thread_init (args)\n"
" cnt = flowintlib.get(\"cnt\")\n"
"end\n"
"\n"
"function match(args)\n"
" print \"inspecting\""
" a = SCFlowintGet(0)\n"
" a = cnt:value()\n"
" if a then\n"
" SCFlowintSet(0, a + 1)\n"
" cnt:set(a + 1)\n"
" else\n"
" SCFlowintSet(0, 1)\n"
" cnt:set(1)\n"
" end\n"
" \n"
" a = SCFlowintGet(0)\n"
" a = cnt:value()\n"
" if a == 2 then\n"
" print \"match\"\n"
" return 1\n"
@@ -1739,15 +1747,19 @@ static int LuaMatchTest04a(void)
/** \test http buffer, flowints */
static int LuaMatchTest05(void)
{
const char script[] = "function init (args)\n"
" local needs = {}\n"
" needs[\"flowint\"] = {\"cnt\"}\n"
" return needs\n"
const char script[] = "local flowintlib = require(\"suricata.flowint\")\n"
"function init (args)\n"
" flowintlib.register(\"cnt\")\n"
" return {}\n"
"end\n"
"\n"
"function thread_init (args)\n"
" cnt = flowintlib.get(\"cnt\")\n"
"end\n"
"\n"
"function match(args)\n"
" print \"inspecting\""
" a = ScFlowintIncr(0)\n"
" a = cnt:incr()\n"
" if a == 2 then\n"
" print \"match\"\n"
" return 1\n"
@@ -1850,15 +1862,19 @@ static int LuaMatchTest05(void)
/** \test http buffer, flowints */
static int LuaMatchTest05a(void)
{
const char script[] = "function init (args)\n"
" local needs = {}\n"
" needs[\"flowint\"] = {\"cnt\"}\n"
" return needs\n"
const char script[] = "local flowintlib = require(\"suricata.flowint\")\n"
"function init (args)\n"
" flowintlib.register(\"cnt\")\n"
" return {}\n"
"end\n"
"\n"
"function thread_init (args)\n"
" cnt = flowintlib.get(\"cnt\")\n"
"end\n"
"\n"
"function match(args)\n"
" print \"inspecting\""
" a = SCFlowintIncr(0)\n"
" a = cnt:incr()\n"
" if a == 2 then\n"
" print \"match\"\n"
" return 1\n"
@@ -1961,20 +1977,24 @@ static int LuaMatchTest05a(void)
/** \test http buffer, flowints */
static int LuaMatchTest06(void)
{
const char script[] = "function init (args)\n"
" local needs = {}\n"
" needs[\"flowint\"] = {\"cnt\"}\n"
" return needs\n"
const char script[] = "local flowintlib = require(\"suricata.flowint\")\n"
"function init (args)\n"
" flowintlib.register(\"cnt\")\n"
" return {}\n"
"end\n"
"\n"
"function thread_init (args)\n"
" cnt = flowintlib.get(\"cnt\")\n"
"end\n"
"\n"
"function match(args)\n"
" print \"inspecting\""
" a = ScFlowintGet(0)\n"
" a = cnt:value()\n"
" if a == nil then\n"
" print \"new var set to 2\""
" ScFlowintSet(0, 2)\n"
" cnt:set(2)\n"
" end\n"
" a = ScFlowintDecr(0)\n"
" a = cnt:decr()\n"
" if a == 0 then\n"
" print \"match\"\n"
" return 1\n"
@@ -2077,20 +2097,24 @@ static int LuaMatchTest06(void)
/** \test http buffer, flowints */
static int LuaMatchTest06a(void)
{
const char script[] = "function init (args)\n"
" local needs = {}\n"
" needs[\"flowint\"] = {\"cnt\"}\n"
" return needs\n"
const char script[] = "local flowintlib = require(\"suricata.flowint\")\n"
"function init (args)\n"
" flowintlib.register(\"cnt\")\n"
" return {}\n"
"end\n"
"\n"
"function thread_init (args)\n"
" cnt = flowintlib.get(\"cnt\")\n"
"end\n"
"\n"
"function match(args)\n"
" print \"inspecting\""
" a = SCFlowintGet(0)\n"
" a = cnt:value()\n"
" if a == nil then\n"
" print \"new var set to 2\""
" SCFlowintSet(0, 2)\n"
" cnt:set(2)\n"
" end\n"
" a = SCFlowintDecr(0)\n"
" a = cnt:decr()\n"
" if a == 0 then\n"
" print \"match\"\n"
" return 1\n"
+2
View File
@@ -20,6 +20,7 @@
#include "util-lua-base64lib.h"
#include "util-lua-dataset.h"
#include "util-lua-dnp3.h"
#include "util-lua-flowintlib.h"
#include "util-lua-flowvarlib.h"
#include "util-lua-http.h"
#include "util-lua-dns.h"
@@ -37,6 +38,7 @@ static const luaL_Reg builtins[] = {
{ "suricata.dnp3", SCLuaLoadDnp3Lib },
{ "suricata.dns", SCLuaLoadDnsLib },
{ "suricata.flow", LuaLoadFlowLib },
{ "suricata.flowint", LuaLoadFlowintLib },
{ "suricata.flowvar", LuaLoadFlowvarLib },
{ "suricata.hashlib", SCLuaLoadHashlib },
{ "suricata.http", SCLuaLoadHttpLib },
+189
View File
@@ -0,0 +1,189 @@
/* Copyright (C) 2025 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "suricata-common.h"
#include "app-layer-protos.h"
#include "flow-var.h"
#include "lauxlib.h"
#include "util-debug.h"
#include "util-lua-common.h"
#include "util-lua-flowintlib.h"
#include "util-lua.h"
#include "util-var-name.h"
#include "detect-lua.h"
#include "detect-lua-extensions.h"
static const char suricata_flowint_mt[] = "suricata:flowint:mt";
static DetectLuaData *GetLuaData(lua_State *luastate)
{
DetectLuaData *ld;
lua_pushlightuserdata(luastate, (void *)&luaext_key_ld);
lua_gettable(luastate, LUA_REGISTRYINDEX);
ld = lua_touserdata(luastate, -1);
return ld;
}
/**
* \brief Register a flowvar.
*
* Ensures that a flowvar exists for the provided name, will be
* created if needed.
*
* The flowvar ID is returned, however as this is most likely to be
* used in the scripts "init" method, this ID is unlikely to be used.
*/
static int LuaFlowintRegister(lua_State *L)
{
DetectLuaData *ld = GetLuaData(L);
const char *name = luaL_checkstring(L, 1);
uint32_t *flowvar_id = lua_newuserdata(L, sizeof(*flowvar_id));
*flowvar_id = VarNameStoreRegister(name, VAR_TYPE_FLOW_INT);
if (*flowvar_id == 0) {
return luaL_error(L, "failed to register flowvar");
}
ld->flowint[ld->flowints++] = *flowvar_id;
luaL_getmetatable(L, suricata_flowint_mt);
lua_setmetatable(L, -2);
return 1;
}
static int LuaFlowintGet(lua_State *L)
{
const char *name = luaL_checkstring(L, 1);
uint32_t *flowvar_id = lua_newuserdata(L, sizeof(*flowvar_id));
*flowvar_id = VarNameStoreLookupByName(name, VAR_TYPE_FLOW_INT);
if (*flowvar_id == 0) {
return luaL_error(L, "flowvar does not exist");
}
luaL_getmetatable(L, suricata_flowint_mt);
lua_setmetatable(L, -2);
return 1;
}
static int LuaFlowintValue(lua_State *L)
{
uint32_t *flowvar_id = luaL_checkudata(L, 1, suricata_flowint_mt);
Flow *f = LuaStateGetFlow(L);
if (f == NULL) {
return LuaCallbackError(L, "flow is NULL");
}
FlowVar *fv = FlowVarGet(f, *flowvar_id);
if (fv == NULL) {
lua_pushnil(L);
} else {
lua_pushnumber(L, (lua_Number)fv->data.fv_int.value);
}
return 1;
}
static int LuaFlowintSet(lua_State *L)
{
const int value = luaL_checkinteger(L, 2);
uint32_t *flowvar_id = luaL_checkudata(L, 1, suricata_flowint_mt);
Flow *f = LuaStateGetFlow(L);
if (f == NULL) {
return luaL_error(L, "no flow");
}
FlowVarAddInt(f, *flowvar_id, value);
return 1;
}
static int LuaFlowintIncr(lua_State *L)
{
uint32_t *flowvar_id = luaL_checkudata(L, 1, suricata_flowint_mt);
Flow *f = LuaStateGetFlow(L);
if (f == NULL) {
return luaL_error(L, "no flow");
}
FlowVar *fv = FlowVarGet(f, *flowvar_id);
uint32_t value;
if (fv == NULL) {
value = 1;
} else {
value = fv->data.fv_int.value;
if (value < UINT32_MAX) {
value++;
}
}
FlowVarAddInt(f, *flowvar_id, value);
lua_pushnumber(L, (lua_Number)value);
return 1;
}
static int LuaFlowintDecr(lua_State *L)
{
uint32_t *flowvar_id = luaL_checkudata(L, 1, suricata_flowint_mt);
Flow *f = LuaStateGetFlow(L);
if (f == NULL) {
return luaL_error(L, "no flow");
}
FlowVar *fv = FlowVarGet(f, *flowvar_id);
uint32_t value;
if (fv == NULL) {
value = 0;
} else {
value = fv->data.fv_int.value;
if (value > 0) {
value--;
}
}
FlowVarAddInt(f, *flowvar_id, value);
lua_pushnumber(L, (lua_Number)value);
return 1;
}
static const luaL_Reg flowvarlib[] = {
// clang-format off
{ "register", LuaFlowintRegister, },
{ "get", LuaFlowintGet },
{ NULL, NULL, },
// clang-format on
};
static const luaL_Reg flowvarmt[] = {
// clang-format off
{ "value", LuaFlowintValue, },
{ "set", LuaFlowintSet, },
{ "incr", LuaFlowintIncr, },
{ "decr", LuaFlowintDecr, },
{ NULL, NULL, },
// clang-format on
};
int LuaLoadFlowintLib(lua_State *L)
{
luaL_newmetatable(L, suricata_flowint_mt);
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
luaL_setfuncs(L, flowvarmt, 0);
luaL_newlib(L, flowvarlib);
return 1;
}
+25
View File
@@ -0,0 +1,25 @@
/* Copyright (C) 2025 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#ifndef SURICATA_UTIL_LUA_FLOWINTLIB_H
#define SURICATA_UTIL_LUA_FLOWINTLIB_H
#include "lua.h"
int LuaLoadFlowintLib(lua_State *L);
#endif /* SURICATA_UTIL_LUA_FLOWINTLIB_H */