lua: convert flowvar functions to lib

New Lua lib, "suricata.flowvar" for working with flowvars from Lua.

Replaces functions:
- SCFlowvarGet (and ScFlowvarGet)
- SCFlowvarSet (and SCFlowvarSet)

Of note, the DetectLuaData has been made available to the init and
thread_init methods, instead of just the match. This is due to an
issue that if a flow variable is not registered in init, it will not
be logged, registering in thread_init is too late.

Ticket: #7486
pull/13097/head
Jason Ish 1 year ago
parent daabab7381
commit 35b03b4077

@ -0,0 +1,79 @@
Flowvar
#######
The ``suricata.flowvar`` library exposes flow variables to Lua
scripts.
Initialization
--------------
First, the ``flowvar`` lib module must be loaded::
local flowvarlib = require("suricata.flow")
Then in the ``init`` method, any flow variables used in the script
should be registered. This is optional and could be skipped if you
know for sure the flow variable will be registered by some other
means.
Example::
local flowvarlib = require("suricata.flow")
function init ()
flowvarlib.register("count")
return {}
end
Finally, in the ``thread_init`` function a handle is acquired for the
flow variables and stored as a global::
function thread_init ()
count_flow_var = flowvarlib.get("count")
end
Flow Variable Methods
---------------------
``value()``
^^^^^^^^^^^
Get the current value of the flow variable as a string. Note that
``nil`` may be returned if the flow variable does not have a value.
``set(value, len)``
^^^^^^^^^^^^^^^^^^^
Set the value of the flow variable to the value provided. The length
of the value must also be provided.
Example
-------
::
local flowvarlib = require("suricata.flowvar")
function init ()
flowvarlib.register("count")
return {}
end
function thread_init ()
count_var = flowvarlib.get("count")
end
function match ()
local value = count_var:value()
if value == nil then
-- Initialize value to 1.
value = tostring(1)
count_var:set(value, #value)
else
value = tostring(tonumber(value) + 1)
count_var:set(value, #value)
fi
-- Return 1 or 0 based on your own logic.
return 1
end

@ -11,6 +11,7 @@ environment without access to additional modules.
base64
dns
flowlib
flowvar
hashlib
http
packetlib

@ -675,38 +675,6 @@ SCFlowintDecr
Decrement Flowint at index given by the first parameter.
SCFlowvarGet
~~~~~~~~~~~~
Get the Flowvar at index given by the parameter.
SCFlowvarSet
~~~~~~~~~~~~
Set a Flowvar. First parameter is the index, second is the data
and third is the length of data.
You can use it to set string
::
function init (args)
local needs = {}
needs["http.request_headers"] = tostring(true)
needs["flowvar"] = {"cnt"}
return needs
end
function match(args)
a = SCFlowvarGet(0);
if a then
a = tostring(tonumber(a)+1)
SCFlowvarSet(0, a, #a)
else
a = tostring(1)
SCFlowvarSet(0, a, #a)
end
Misc
----

@ -526,6 +526,7 @@ noinst_HEADERS = \
util-lua-dnp3-objects.h \
util-lua-dns.h \
util-lua-flowlib.h \
util-lua-flowvarlib.h \
util-lua.h \
util-lua-hashlib.h \
util-lua-hassh.h \
@ -1094,6 +1095,7 @@ libsuricata_c_a_SOURCES = \
util-lua-dnp3-objects.c \
util-lua-dns.c \
util-lua-flowlib.c \
util-lua-flowvarlib.c \
util-lua-hashlib.c \
util-lua-hassh.c \
util-lua-http.c \

@ -47,7 +47,8 @@
#include "util-lua-dnp3.h"
#include "detect-lua-extensions.h"
static const char luaext_key_ld[] = "suricata:luadata";
/* Lua registry key for DetectLuaData. */
const char luaext_key_ld[] = "suricata:luadata";
static int GetLuaData(lua_State *luastate, DetectLuaData **ret_ld)
{
@ -74,67 +75,6 @@ static int GetFlow(lua_State *luastate, Flow **ret_f)
return 0;
}
static int GetFlowVarById(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->flowvar[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 GetFlowVarByKey(lua_State *luastate, Flow *f, FlowVar **ret_fv)
{
*ret_fv = NULL;
if (!lua_isstring(luastate, 1)) {
LUA_ERROR("flowvar key not a string");
}
const char *keystr = lua_tostring(luastate, 1);
if (keystr == NULL) {
LUA_ERROR("key is null");
}
if (!lua_isnumber(luastate, 2)) {
LUA_ERROR("key length not specified");
}
int keylen = lua_tonumber(luastate, 2);
if (keylen < 0 || keylen > 0xff) {
LUA_ERROR("key len out of range: max 256");
}
FlowVar *fv = FlowVarGetByKey(f, (const uint8_t *)keystr, (uint8_t)keylen);
if (fv == NULL) {
LUA_ERROR("no flow var");
}
*ret_fv = fv;
return 0;
}
static int GetFlowIntById(lua_State *luastate, Flow *f,
FlowVar **ret_fv, bool fv_may_be_null, uint32_t *ret_idx)
{
@ -169,151 +109,6 @@ static int GetFlowIntById(lua_State *luastate, Flow *f,
return 0;
}
static int LuaGetFlowvar(lua_State *luastate)
{
Flow *f;
FlowVar *fv;
int ret;
/* need flow */
ret = GetFlow(luastate, &f);
if (ret != 0)
return ret;
if (lua_isnumber(luastate, 1)) {
ret = GetFlowVarById(luastate, f, &fv, false, NULL);
if (ret != 0 || fv == NULL)
return ret;
} else if (lua_isstring(luastate, 1)) {
ret = GetFlowVarByKey(luastate, f, &fv);
if (ret != 0 || fv == NULL)
return ret;
} else {
LUA_ERROR("invalid data type as first argument");
}
LuaPushStringBuffer(luastate,
(const uint8_t *)fv->data.fv_str.value,
(size_t)fv->data.fv_str.value_len);
return 1;
}
static int LuaSetFlowvarById(lua_State *luastate)
{
uint32_t idx = 0;
Flow *f;
const char *str;
int len;
uint8_t *buffer;
FlowVar *fv = NULL;
/* need flow */
int ret = GetFlow(luastate, &f);
if (ret != 0)
return ret;
ret = GetFlowVarById(luastate, f, &fv, true, &idx);
if (ret != 0)
return ret;
if (!lua_isstring(luastate, 2)) {
LUA_ERROR("buffer not a string");
}
str = lua_tostring(luastate, 2);
if (str == NULL) {
LUA_ERROR("buffer is null");
}
if (!lua_isnumber(luastate, 3)) {
LUA_ERROR("buffer length not specified");
}
len = lua_tonumber(luastate, 3);
if (len < 0 || len > 0xffff) {
LUA_ERROR("len out of range: max 64k");
}
buffer = SCMalloc(len+1);
if (unlikely(buffer == NULL)) {
LUA_ERROR("out of memory");
}
memcpy(buffer, str, len);
buffer[len] = '\0';
FlowVarAddIdValue(f, idx, buffer, (uint16_t)len);
return 0;
}
static int LuaSetFlowvarByKey(lua_State *luastate)
{
Flow *f;
const char *str;
int len;
uint8_t *buffer;
/* need flow */
int ret = GetFlow(luastate, &f);
if (ret != 0)
return ret;
const char *keystr = NULL;
int keylen = 0;
keystr = lua_tostring(luastate, 1);
if (keystr == NULL) {
LUA_ERROR("key is null");
}
if (!lua_isnumber(luastate, 2)) {
LUA_ERROR("key length not specified");
}
keylen = lua_tonumber(luastate, 2);
if (keylen < 0 || keylen > 0xff) {
LUA_ERROR("key len out of range: max 255");
}
if (!lua_isstring(luastate, 3)) {
LUA_ERROR("buffer not a string");
}
str = lua_tostring(luastate, 3);
if (str == NULL) {
LUA_ERROR("buffer is null");
}
if (!lua_isnumber(luastate, 4)) {
LUA_ERROR("buffer length not specified");
}
len = lua_tonumber(luastate, 4);
if (len < 0 || len > 0xffff) {
LUA_ERROR("len out of range: max 64k");
}
buffer = SCMalloc(len+1);
if (unlikely(buffer == NULL)) {
LUA_ERROR("out of memory");
}
memcpy(buffer, str, len);
buffer[len] = '\0';
uint8_t *keybuf = SCMalloc(keylen+1);
if (unlikely(keybuf == NULL)) {
SCFree(buffer);
LUA_ERROR("out of memory");
}
memcpy(keybuf, keystr, keylen);
keybuf[keylen] = '\0';
FlowVarAddKeyValue(f, keybuf, (uint8_t)keylen, buffer, (uint16_t)len);
return 0;
}
static int LuaSetFlowvar(lua_State *luastate)
{
if (lua_isnumber(luastate, 1)) {
return LuaSetFlowvarById(luastate);
} else {
return LuaSetFlowvarByKey(luastate);
}
}
static int LuaGetFlowint(lua_State *luastate)
{
Flow *f;
@ -478,13 +273,7 @@ void LuaExtensionsMatchSetup(lua_State *lua_state, DetectLuaData *ld,
{
SCLogDebug("det_ctx %p, f %p", det_ctx, f);
/* lua keyword data */
lua_pushlightuserdata(lua_state, (void *)&luaext_key_ld);
lua_pushlightuserdata(lua_state, (void *)ld);
lua_settable(lua_state, LUA_REGISTRYINDEX);
LuaStateSetSignature(lua_state, s);
LuaStateSetFlow(lua_state, f);
LuaStateSetDetCtx(lua_state, det_ctx);
@ -508,18 +297,6 @@ void LuaExtensionsMatchSetup(lua_State *lua_state, DetectLuaData *ld,
*/
int LuaRegisterExtensions(lua_State *lua_state)
{
lua_pushcfunction(lua_state, LuaGetFlowvar);
lua_setglobal(lua_state, "ScFlowvarGet");
lua_pushcfunction(lua_state, LuaGetFlowvar);
lua_setglobal(lua_state, "SCFlowvarGet");
lua_pushcfunction(lua_state, LuaSetFlowvar);
lua_setglobal(lua_state, "ScFlowvarSet");
lua_pushcfunction(lua_state, LuaSetFlowvar);
lua_setglobal(lua_state, "SCFlowvarSet");
lua_pushcfunction(lua_state, LuaGetFlowint);
lua_setglobal(lua_state, "ScFlowintGet");

@ -24,6 +24,8 @@
#ifndef SURICATA_DETECT_LUA_EXT_H
#define SURICATA_DETECT_LUA_EXT_H
extern const char luaext_key_ld[];
int LuaRegisterExtensions(lua_State *);
void LuaExtensionsMatchSetup(lua_State *lua_state, DetectLuaData *, DetectEngineThreadCtx *det_ctx,

@ -146,6 +146,13 @@ void LuaDumpStack(lua_State *state, const char *prefix)
}
}
static void LuaStateSetDetectLuaData(lua_State *state, DetectLuaData *data)
{
lua_pushlightuserdata(state, (void *)&luaext_key_ld);
lua_pushlightuserdata(state, (void *)data);
lua_settable(state, LUA_REGISTRYINDEX);
}
/**
* \brief Common function to run the Lua match function and process
* the return value.
@ -406,6 +413,7 @@ static void *DetectLuaThreadInit(void *data)
}
LuaRegisterExtensions(t->luastate);
LuaStateSetDetectLuaData(t->luastate, lua);
/* hackish, needed to allow unittests to pass buffers as scripts instead of files */
#ifdef UNITTESTS
@ -513,6 +521,7 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld, const
} else {
SCLuaSbLoadLibs(luastate);
}
LuaStateSetDetectLuaData(luastate, ld);
/* hackish, needed to allow unittests to pass buffers as scripts instead of files */
#ifdef UNITTESTS
@ -804,22 +813,25 @@ static int LuaMatchTest01(void)
{
SCConfSetFinal("security.lua.allow-rules", "true");
const char script[] = "function init (args)\n"
" local needs = {}\n"
" needs[\"flowvar\"] = {\"cnt\"}\n"
" return needs\n"
const char script[] = "local flowvarlib = require(\"suricata.flowvar\")\n"
"function init (args)\n"
" flowvarlib.register(\"cnt\")\n"
" return {}\n"
"end\n"
"function thread_init (args)\n"
" cnt = flowvarlib.get(\"cnt\")\n"
"end\n"
"\n"
"function match(args)\n"
" a = ScFlowvarGet(0)\n"
" a = cnt:value()\n"
" if a then\n"
" a = tostring(tonumber(a)+1)\n"
" print (a)\n"
" ScFlowvarSet(0, a, #a)\n"
" cnt:set(a, #a)\n"
" else\n"
" a = tostring(1)\n"
" print (a)\n"
" ScFlowvarSet(0, a, #a)\n"
" cnt:set(a, #a)\n"
" end\n"
" \n"
" print (\"pre check: \" .. (a))\n"
@ -926,22 +938,25 @@ static int LuaMatchTest01(void)
static int LuaMatchTest01a(void)
{
const char script[] = "function init (args)\n"
" local needs = {}\n"
" needs[\"flowvar\"] = {\"cnt\"}\n"
" return needs\n"
const char script[] = "local flowvarlib = require(\"suricata.flowvar\")\n"
"function init (args)\n"
" flowvarlib.register(\"cnt\")\n"
" return {}\n"
"end\n"
"function thread_init (args)\n"
" cnt = flowvarlib.get(\"cnt\")\n"
"end\n"
"\n"
"function match(args)\n"
" a = SCFlowvarGet(0)\n"
" a = cnt:value(0)\n"
" if a then\n"
" a = tostring(tonumber(a)+1)\n"
" print (a)\n"
" SCFlowvarSet(0, a, #a)\n"
" cnt:set(a, #a)\n"
" else\n"
" a = tostring(1)\n"
" print (a)\n"
" SCFlowvarSet(0, a, #a)\n"
" cnt:set(a, #a)\n"
" end\n"
" \n"
" print (\"pre check: \" .. (a))\n"
@ -1047,23 +1062,27 @@ static int LuaMatchTest01a(void)
/** \test payload buffer */
static int LuaMatchTest02(void)
{
const char script[] = "function init (args)\n"
const char script[] = "local flowvarlib = require(\"suricata.flowvar\")\n"
"function init (args)\n"
" flowvarlib.register(\"cnt\")\n"
" local needs = {}\n"
" needs[\"payload\"] = tostring(true)\n"
" needs[\"flowvar\"] = {\"cnt\"}\n"
" return needs\n"
"end\n"
"function thread_init (args)\n"
" cnt = flowvarlib.get(\"cnt\")\n"
"end\n"
"\n"
"function match(args)\n"
" a = ScFlowvarGet(0)\n"
" a = cnt:value()\n"
" if a then\n"
" a = tostring(tonumber(a)+1)\n"
" print (a)\n"
" ScFlowvarSet(0, a, #a)\n"
" cnt:set(a, #a)\n"
" else\n"
" a = tostring(1)\n"
" print (a)\n"
" ScFlowvarSet(0, a, #a)\n"
" cnt:set(a, #a)\n"
" end\n"
" \n"
" print (\"pre check: \" .. (a))\n"
@ -1154,23 +1173,27 @@ static int LuaMatchTest02(void)
/** \test payload buffer */
static int LuaMatchTest02a(void)
{
const char script[] = "function init (args)\n"
const char script[] = "local flowvarlib = require(\"suricata.flowvar\")\n"
"function init (args)\n"
" flowvarlib.register(\"cnt\")"
" local needs = {}\n"
" needs[\"payload\"] = tostring(true)\n"
" needs[\"flowvar\"] = {\"cnt\"}\n"
" return needs\n"
"end\n"
"function thread_init (args)\n"
" cnt = flowvarlib.get(\"cnt\")"
"end\n"
"\n"
"function match(args)\n"
" a = SCFlowvarGet(0)\n"
" a = cnt:value()\n"
" if a then\n"
" a = tostring(tonumber(a)+1)\n"
" print (a)\n"
" SCFlowvarSet(0, a, #a)\n"
" cnt:set(a, #a)\n"
" else\n"
" a = tostring(1)\n"
" print (a)\n"
" SCFlowvarSet(0, a, #a)\n"
" cnt:set(a, #a)\n"
" end\n"
" \n"
" print (\"pre check: \" .. (a))\n"
@ -1260,23 +1283,28 @@ static int LuaMatchTest02a(void)
/** \test packet buffer */
static int LuaMatchTest03(void)
{
const char script[] = "function init (args)\n"
const char script[] = "local flowvarlib = require(\"suricata.flowvar\")\n"
"function init (args)\n"
" flowvarlib.register(\"cnt\")\n"
" local needs = {}\n"
" needs[\"packet\"] = tostring(true)\n"
" needs[\"flowvar\"] = {\"cnt\"}\n"
" return needs\n"
"end\n"
"\n"
"function thread_init (args)\n"
" cnt = flowvarlib.get(\"cnt\")\n"
"end\n"
"\n"
"function match(args)\n"
" a = ScFlowvarGet(0)\n"
" a = cnt:value()\n"
" if a then\n"
" a = tostring(tonumber(a)+1)\n"
" print (a)\n"
" ScFlowvarSet(0, a, #a)\n"
" cnt:set(a, #a)\n"
" else\n"
" a = tostring(1)\n"
" print (a)\n"
" ScFlowvarSet(0, a, #a)\n"
" cnt:set(a, #a)\n"
" end\n"
" \n"
" print (\"pre check: \" .. (a))\n"
@ -1366,23 +1394,28 @@ static int LuaMatchTest03(void)
/** \test packet buffer */
static int LuaMatchTest03a(void)
{
const char script[] = "function init (args)\n"
const char script[] = "local flowvarlib = require(\"suricata.flowvar\")\n"
"function init (args)\n"
" flowvarlib.register(\"cnt\")\n"
" local needs = {}\n"
" needs[\"packet\"] = tostring(true)\n"
" needs[\"flowvar\"] = {\"cnt\"}\n"
" return needs\n"
"end\n"
"\n"
"function thread_init (args)\n"
" cnt = flowvarlib.get(\"cnt\")\n"
"end\n"
"\n"
"function match(args)\n"
" a = SCFlowvarGet(0)\n"
" a = cnt:value()\n"
" if a then\n"
" a = tostring(tonumber(a)+1)\n"
" print (a)\n"
" SCFlowvarSet(0, a, #a)\n"
" cnt:set(a, #a)\n"
" else\n"
" a = tostring(1)\n"
" print (a)\n"
" SCFlowvarSet(0, a, #a)\n"
" cnt:set(a, #a)\n"
" end\n"
" \n"
" print (\"pre check: \" .. (a))\n"

@ -20,6 +20,7 @@
#include "util-lua-base64lib.h"
#include "util-lua-dataset.h"
#include "util-lua-dnp3.h"
#include "util-lua-flowvarlib.h"
#include "util-lua-http.h"
#include "util-lua-dns.h"
#include "util-lua-ssh.h"
@ -36,6 +37,7 @@ static const luaL_Reg builtins[] = {
{ "suricata.dnp3", SCLuaLoadDnp3Lib },
{ "suricata.dns", SCLuaLoadDnsLib },
{ "suricata.flow", LuaLoadFlowLib },
{ "suricata.flowvar", LuaLoadFlowvarLib },
{ "suricata.hashlib", SCLuaLoadHashlib },
{ "suricata.http", SCLuaLoadHttpLib },
{ "suricata.packet", LuaLoadPacketLib },

@ -0,0 +1,142 @@
/* 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-flowvarlib.h"
#include "util-lua.h"
#include "util-var-name.h"
#include "detect-lua.h"
#include "detect-lua-extensions.h"
static const char suricata_flowvar_mt[] = "suricata:flowvar: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 LuaFlowvarRegister(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_VAR);
if (*flowvar_id == 0) {
return luaL_error(L, "failed to register flowvar");
}
ld->flowvar[ld->flowvars++] = *flowvar_id;
luaL_getmetatable(L, suricata_flowvar_mt);
lua_setmetatable(L, -2);
return 1;
}
static int LuaFlowvarGet(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_VAR);
if (*flowvar_id == 0) {
return luaL_error(L, "flowvar does not exist");
}
luaL_getmetatable(L, suricata_flowvar_mt);
lua_setmetatable(L, -2);
return 1;
}
static int LuaFlowvarValue(lua_State *L)
{
uint32_t *flowvar_id = luaL_testudata(L, 1, suricata_flowvar_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 {
LuaPushStringBuffer(
L, (const uint8_t *)fv->data.fv_str.value, (size_t)fv->data.fv_str.value_len);
}
return 1;
}
static int LuaFlowvarSet(lua_State *L)
{
const char *value = luaL_checkstring(L, 2);
const int len = luaL_checkinteger(L, 3);
uint32_t *flowvar_id = luaL_checkudata(L, 1, suricata_flowvar_mt);
Flow *f = LuaStateGetFlow(L);
if (f == NULL) {
return luaL_error(L, "no flow");
}
uint8_t *buf = SCMalloc(len + 1);
memcpy(buf, value, len);
buf[len] = '\0';
FlowVarAddIdValue(f, *flowvar_id, buf, (uint16_t)len);
return 1;
}
static const luaL_Reg flowvarlib[] = {
// clang-format off
{ "register", LuaFlowvarRegister, },
{ "get", LuaFlowvarGet },
{ NULL, NULL, },
// clang-format on
};
static const luaL_Reg flowvarmt[] = {
// clang-format off
{ "value", LuaFlowvarValue, },
{ "set", LuaFlowvarSet, },
{ NULL, NULL, },
// clang-format on
};
int LuaLoadFlowvarLib(lua_State *L)
{
luaL_newmetatable(L, suricata_flowvar_mt);
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
luaL_setfuncs(L, flowvarmt, 0);
luaL_newlib(L, flowvarlib);
return 1;
}

@ -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_FLOWVARLIB_H
#define SURICATA_UTIL_LUA_FLOWVARLIB_H
#include "lua.h"
int LuaLoadFlowvarLib(lua_State *L);
#endif /* SURICATA_UTIL_LUA_FLOWVARLIB_H */
Loading…
Cancel
Save