suricata
util-lua-flowintlib.c
Go to the documentation of this file.
1 /* Copyright (C) 2025 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 #include "suricata-common.h"
19 #include "app-layer-protos.h"
20 #include "flow-var.h"
21 #include "lauxlib.h"
22 #include "util-debug.h"
23 #include "util-lua-common.h"
24 #include "util-lua-flowintlib.h"
25 #include "util-lua.h"
26 #include "util-var-name.h"
27 #include "detect-lua.h"
28 #include "detect-lua-extensions.h"
29 
30 static const char suricata_flowint_mt[] = "suricata:flowint:mt";
31 
32 static DetectLuaData *GetLuaData(lua_State *luastate)
33 {
34  return LuaStateGetDetectLuaData(luastate);
35 }
36 
37 /**
38  * \brief Register a flowvar.
39  *
40  * Ensures that a flowvar exists for the provided name, will be
41  * created if needed.
42  *
43  * The flowvar ID is returned, however as this is most likely to be
44  * used in the scripts "init" method, this ID is unlikely to be used.
45  */
46 static int LuaFlowintRegister(lua_State *L)
47 {
48  DetectLuaData *ld = GetLuaData(L);
49  if (ld == NULL) {
50  return luaL_error(L, "flowint API not available in this context");
51  }
52  if (!ld->register_in_init) {
53  return luaL_error(L, "flowint.register() must be called from init()");
54  }
55  const char *name = luaL_checkstring(L, 1);
56  /* check the limit first: a failed over-limit registration must not
57  * leave a name store entry that nothing unregisters */
58  if (ld->flowints >= DETECT_LUA_MAX_FLOWINTS) {
59  return luaL_error(L, "too many flowints registered");
60  }
61  uint32_t *flowvar_id = SCLuaNewUserData(L, SCLUA_TUD_FLOWINT, sizeof(*flowvar_id));
62  if (flowvar_id == NULL) {
63  return luaL_error(L, "failed to allocate flowint");
64  }
66  if (*flowvar_id == 0) {
67  return luaL_error(L, "failed to register flowint");
68  }
69  ld->flowint[ld->flowints++] = *flowvar_id;
70 
71  luaL_getmetatable(L, suricata_flowint_mt);
72  lua_setmetatable(L, -2);
73 
74  return 1;
75 }
76 
77 static int LuaFlowintGet(lua_State *L)
78 {
79  const char *name = luaL_checkstring(L, 1);
80  uint32_t *flowvar_id = SCLuaNewUserData(L, SCLUA_TUD_FLOWINT, sizeof(*flowvar_id));
81  if (flowvar_id == NULL) {
82  return luaL_error(L, "failed to allocate flowint");
83  }
85  if (*flowvar_id == 0) {
86  return luaL_error(L, "flowvar does not exist");
87  }
88 
89  luaL_getmetatable(L, suricata_flowint_mt);
90  lua_setmetatable(L, -2);
91 
92  return 1;
93 }
94 
95 static int LuaFlowintValue(lua_State *L)
96 {
97  uint32_t *flowvar_id = SCLuaCheckUserData(L, 1, suricata_flowint_mt, SCLUA_TUD_FLOWINT);
98  Flow *f = LuaStateGetFlow(L);
99  if (f == NULL) {
100  return LuaCallbackError(L, "flow is NULL");
101  }
102  FlowVar *fv = FlowVarGet(f, *flowvar_id);
103  if (fv == NULL) {
104  lua_pushnil(L);
105  } else {
106  lua_pushnumber(L, (lua_Number)fv->data.fv_int.value);
107  }
108  return 1;
109 }
110 
111 static int LuaFlowintSet(lua_State *L)
112 {
113  const lua_Integer value = luaL_checkinteger(L, 2);
114  uint32_t *flowvar_id = SCLuaCheckUserData(L, 1, suricata_flowint_mt, SCLUA_TUD_FLOWINT);
115  Flow *f = LuaStateGetFlow(L);
116  if (f == NULL) {
117  return luaL_error(L, "no flow");
118  }
119 
120  /* the stored value is a uint32_t: reject what would truncate
121  * instead of wrapping silently. Compare through int64_t: on ILP32
122  * targets lua_Integer is 32 bits and (lua_Integer)UINT32_MAX wraps
123  * to -1 */
124  const int64_t v = (int64_t)value;
125  if (v < 0 || (uint64_t)v > (uint64_t)UINT32_MAX) {
126  return luaL_error(L, "value out of range: must be 0..4294967295");
127  }
128 
129  FlowVarAddInt(f, *flowvar_id, (uint32_t)value);
130 
131  /* set() documents no result; claiming one hands back the last
132  * argument (or the flow lock hint left by LuaStateGetFlow) */
133  return 0;
134 }
135 
136 static int LuaFlowintIncr(lua_State *L)
137 {
138  uint32_t *flowvar_id = SCLuaCheckUserData(L, 1, suricata_flowint_mt, SCLUA_TUD_FLOWINT);
139  Flow *f = LuaStateGetFlow(L);
140  if (f == NULL) {
141  return luaL_error(L, "no flow");
142  }
143 
144  FlowVar *fv = FlowVarGet(f, *flowvar_id);
145  uint32_t value;
146  if (fv == NULL) {
147  value = 1;
148  } else {
149  value = fv->data.fv_int.value;
150  if (value < UINT32_MAX) {
151  value++;
152  }
153  }
154 
155  FlowVarAddInt(f, *flowvar_id, value);
156  lua_pushnumber(L, (lua_Number)value);
157 
158  return 1;
159 }
160 
161 static int LuaFlowintDecr(lua_State *L)
162 {
163  uint32_t *flowvar_id = SCLuaCheckUserData(L, 1, suricata_flowint_mt, SCLUA_TUD_FLOWINT);
164  Flow *f = LuaStateGetFlow(L);
165  if (f == NULL) {
166  return luaL_error(L, "no flow");
167  }
168 
169  FlowVar *fv = FlowVarGet(f, *flowvar_id);
170  uint32_t value;
171  if (fv == NULL) {
172  value = 0;
173  } else {
174  value = fv->data.fv_int.value;
175  if (value > 0) {
176  value--;
177  }
178  }
179 
180  FlowVarAddInt(f, *flowvar_id, value);
181  lua_pushnumber(L, (lua_Number)value);
182 
183  return 1;
184 }
185 
186 static const luaL_Reg flowvarlib[] = {
187  // clang-format off
188  { "register", LuaFlowintRegister, },
189  { "get", LuaFlowintGet },
190  { NULL, NULL, },
191  // clang-format on
192 };
193 
194 static const luaL_Reg flowvarmt[] = {
195  // clang-format off
196  { "value", LuaFlowintValue, },
197  { "set", LuaFlowintSet, },
198  { "incr", LuaFlowintIncr, },
199  { "decr", LuaFlowintDecr, },
200  { NULL, NULL, },
201  // clang-format on
202 };
203 
205 {
206  luaL_newmetatable(L, suricata_flowint_mt);
207  lua_pushvalue(L, -1);
208  lua_setfield(L, -2, "__index");
209  luaL_setfuncs(L, flowvarmt, 0);
210 
211  luaL_newlib(L, flowvarlib);
212  return 1;
213 }
DetectLuaData
Definition: detect-lua.h:44
util-lua-common.h
name
const char * name
Definition: detect-engine-proto.c:47
util-lua.h
LuaCallbackError
int LuaCallbackError(lua_State *luastate, const char *msg)
Definition: util-lua-common.c:218
Flow_
Flow data structure.
Definition: flow.h:359
detect-lua.h
util-var-name.h
VarNameStoreRegister
uint32_t VarNameStoreRegister(const char *name, const enum VarTypes type)
Definition: util-var-name.c:156
lua_State
struct lua_State lua_State
Definition: suricata-common.h:527
DetectLuaData::register_in_init
bool register_in_init
Definition: detect-lua.h:60
FlowVar_::fv_int
FlowVarTypeInt fv_int
Definition: flow-var.h:65
VarNameStoreLookupByName
uint32_t VarNameStoreLookupByName(const char *name, const enum VarTypes type)
find name for id+type at packet time. As the active store won't be modified, we don't need locks.
Definition: util-var-name.c:327
util-debug.h
DETECT_LUA_MAX_FLOWINTS
#define DETECT_LUA_MAX_FLOWINTS
Definition: detect-lua.h:36
SCLuaCheckUserData
void * SCLuaCheckUserData(lua_State *L, int idx, const char *mt, uint32_t type_id)
Definition: util-lua-common.c:101
DetectLuaData::flowints
uint16_t flowints
Definition: detect-lua.h:53
DetectLuaData::flowint
uint32_t flowint[DETECT_LUA_MAX_FLOWINTS]
Definition: detect-lua.h:52
LuaStateGetDetectLuaData
DetectLuaData * LuaStateGetDetectLuaData(lua_State *luastate)
get the per-rule DetectLuaData
Definition: util-lua.c:319
FlowVarTypeInt_::value
uint32_t value
Definition: flow-var.h:46
SCLuaNewUserData
void * SCLuaNewUserData(lua_State *L, uint32_t type_id, size_t size)
Definition: util-lua-common.c:42
detect-lua-extensions.h
suricata-common.h
FlowVar_::data
union FlowVar_::@121 data
util-lua-flowintlib.h
FlowVarAddInt
void FlowVarAddInt(Flow *f, uint32_t idx, uint32_t value)
Definition: flow-var.c:183
LuaStateGetFlow
Flow * LuaStateGetFlow(lua_State *luastate)
get flow pointer from lua state
Definition: util-lua.c:260
VAR_TYPE_FLOW_INT
@ VAR_TYPE_FLOW_INT
Definition: util-var.h:37
app-layer-protos.h
FlowVarGet
FlowVar * FlowVarGet(Flow *f, uint32_t idx)
get the flowvar with index 'idx' from the flow
Definition: flow-var.c:84
SCLUA_TUD_FLOWINT
@ SCLUA_TUD_FLOWINT
Definition: util-lua-common.h:54
flow-var.h
FlowVar_
Definition: flow-var.h:55
LuaLoadFlowintLib
int LuaLoadFlowintLib(lua_State *L)
Definition: util-lua-flowintlib.c:204
f
Flow f
Definition: fuzz_dataset.c:32