suricata
util-lua-flowlib.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/**
19 * \file
20 *
21 * Flow API fow Lua.
22 *
23 * local flow = require("suricata.flow")
24 */
25
26#include "suricata-common.h"
27
28#include "util-lua-flowlib.h"
29
30#include "app-layer-protos.h" /* Required by util-lua-common. */
31#include "util-lua-common.h"
32#include "util-lua.h"
33#include "util-debug.h"
34#include "util-print.h"
35
36/* key for f (flow) pointer */
37extern const char lua_ext_key_f[];
38static const char suricata_flow[] = "suricata:flow";
39
40struct LuaFlow {
42};
43
44static int LuaFlowGC(lua_State *luastate)
45{
46 SCLogDebug("gc:start");
47 struct LuaFlow *s = (struct LuaFlow *)lua_touserdata(luastate, 1);
48 SCLogDebug("flow %p", s->f);
49 s->f = NULL;
50 SCLogDebug("gc:done");
51 return 0;
52}
53
54/** \internal
55 * \brief fill lua stack with flow id
56 * \param luastate the lua state
57 * \retval cnt number of data items placed on the stack
58 *
59 * Places: flow id (number)
60 */
61static int LuaFlowId(lua_State *luastate)
62{
63 struct LuaFlow *s = (struct LuaFlow *)lua_touserdata(luastate, 1);
64 if (s == NULL || s->f == NULL) {
65 LUA_ERROR("failed to get flow");
66 }
67
68 Flow *f = s->f;
69
70 int64_t id = (int64_t)FlowGetId(f);
71 lua_pushinteger(luastate, id);
72 return 1;
73}
74
75/** \internal
76 * \brief fill lua stack with AppLayerProto
77 * \param luastate the lua state
78 * \retval cnt number of data items placed on the stack
79 *
80 * Places: alproto as string (string), alproto_ts as string (string),
81 * alproto_tc as string (string), alproto_orig as string (string),
82 * alproto_expect as string (string)
83 */
84static int LuaFlowAppLayerProto(lua_State *luastate)
85{
86 struct LuaFlow *s = (struct LuaFlow *)lua_touserdata(luastate, 1);
87 if (s == NULL || s->f == NULL) {
88 LUA_ERROR("failed to get flow");
89 }
90
91 Flow *f = s->f;
92 lua_pushstring(luastate, AppProtoToString(f->alproto));
93 lua_pushstring(luastate, AppProtoToString(f->alproto_ts));
94 lua_pushstring(luastate, AppProtoToString(f->alproto_tc));
95 lua_pushstring(luastate, AppProtoToString(f->alproto_orig));
96 lua_pushstring(luastate, AppProtoToString(f->alproto_expect));
97 return 5;
98}
99
100/** \internal
101 * \brief fill lua stack with flow has alerts
102 * \param luastate the lua state
103 * \retval cnt number of data items placed on the stack
104 *
105 * Places: alerts (bool)
106 */
107static int LuaFlowHasAlerts(lua_State *luastate)
108{
109 struct LuaFlow *s = (struct LuaFlow *)lua_touserdata(luastate, 1);
110 if (s == NULL || s->f == NULL) {
111 LUA_ERROR("failed to get flow");
112 }
113
114 Flow *f = s->f;
115 lua_pushboolean(luastate, FlowHasAlerts(f));
116 return 1;
117}
118
119/** \internal
120 * \brief fill lua stack with flow stats
121 * \param luastate the lua state
122 * \retval cnt number of data items placed on the stack
123 *
124 * Places: ts pkts (number), ts bytes (number), tc pkts (number), tc bytes (number)
125 */
126static int LuaFlowStats(lua_State *luastate)
127{
128 struct LuaFlow *s = (struct LuaFlow *)lua_touserdata(luastate, 1);
129 if (s == NULL || s->f == NULL) {
130 LUA_ERROR("failed to get flow");
131 }
132
133 Flow *f = s->f;
134 lua_pushinteger(luastate, f->todstpktcnt);
135 lua_pushinteger(luastate, f->todstbytecnt);
136 lua_pushinteger(luastate, f->tosrcpktcnt);
137 lua_pushinteger(luastate, f->tosrcbytecnt);
138 return 4;
139}
140
141/** \internal
142 * \brief fill lua stack with flow timestamps
143 * \param luastate the lua state
144 * \retval cnt number of data items placed on the stack
145 *
146 * Places: seconds (number), seconds (number), microseconds (number),
147 * microseconds (number)
148 */
149static int LuaFlowTimestamps(lua_State *luastate)
150{
151 struct LuaFlow *s = (struct LuaFlow *)lua_touserdata(luastate, 1);
152 if (s == NULL || s->f == NULL) {
153 LUA_ERROR("failed to get flow");
154 }
155
156 Flow *f = s->f;
157 lua_pushnumber(luastate, (double)SCTIME_SECS(f->startts));
158 lua_pushnumber(luastate, (double)SCTIME_SECS(f->lastts));
159 lua_pushnumber(luastate, (double)SCTIME_USECS(f->startts));
160 lua_pushnumber(luastate, (double)SCTIME_USECS(f->lastts));
161 return 4;
162}
163
164static int LuaFlowTimestringIso8601(lua_State *luastate)
165{
166 struct LuaFlow *s = (struct LuaFlow *)lua_touserdata(luastate, 1);
167 if (s == NULL || s->f == NULL) {
168 LUA_ERROR("failed to get flow");
169 }
170
171 Flow *f = s->f;
172 char timebuf[64];
173 CreateIsoTimeString(f->startts, timebuf, sizeof(timebuf));
174 lua_pushstring(luastate, timebuf);
175 return 1;
176}
177
178/** \internal
179 * \brief legacy format as used by fast.log, http.log, etc.
180 */
181static int LuaFlowTimestringLegacy(lua_State *luastate)
182{
183 struct LuaFlow *s = (struct LuaFlow *)lua_touserdata(luastate, 1);
184 if (s == NULL || s->f == NULL) {
185 LUA_ERROR("failed to get flow");
186 }
187
188 Flow *f = s->f;
189 char timebuf[64];
190 CreateTimeString(f->startts, timebuf, sizeof(timebuf));
191 lua_pushstring(luastate, timebuf);
192 return 1;
193}
194
195/** \internal
196 * \brief fill lua stack with header info
197 * \param luastate the lua state
198 * \retval cnt number of data items placed on the stack
199 *
200 * Places: ipver (number), src ip (string), dst ip (string), protocol (number),
201 * sp or icmp type (number), dp or icmp code (number).
202 */
203static int LuaFlowTuple(lua_State *luastate)
204{
205 struct LuaFlow *s = (struct LuaFlow *)lua_touserdata(luastate, 1);
206 if (s == NULL || s->f == NULL) {
207 LUA_ERROR("failed to get flow");
208 }
209 Flow *f = s->f;
210 int ipver = 0;
211 if (FLOW_IS_IPV4(f)) {
212 ipver = 4;
213 } else if (FLOW_IS_IPV6(f)) {
214 ipver = 6;
215 }
216 lua_pushinteger(luastate, ipver);
217 if (ipver == 0)
218 return 1;
219
220 char srcip[46] = "", dstip[46] = "";
221 if (FLOW_IS_IPV4(f)) {
222 PrintInet(AF_INET, (const void *)&(f->src.addr_data32[0]), srcip, sizeof(srcip));
223 PrintInet(AF_INET, (const void *)&(f->dst.addr_data32[0]), dstip, sizeof(dstip));
224 } else if (FLOW_IS_IPV6(f)) {
225 PrintInet(AF_INET6, (const void *)&(f->src.address), srcip, sizeof(srcip));
226 PrintInet(AF_INET6, (const void *)&(f->dst.address), dstip, sizeof(dstip));
227 }
228
229 lua_pushstring(luastate, srcip);
230 lua_pushstring(luastate, dstip);
231
232 /* proto and ports (or type/ code) */
233 lua_pushinteger(luastate, f->proto);
234 if (f->proto == IPPROTO_TCP || f->proto == IPPROTO_UDP) {
235 lua_pushinteger(luastate, f->sp);
236 lua_pushinteger(luastate, f->dp);
237 } else if (f->proto == IPPROTO_ICMP || f->proto == IPPROTO_ICMPV6) {
238 lua_pushinteger(luastate, f->icmp_s.type);
239 lua_pushinteger(luastate, f->icmp_s.code);
240 } else {
241 lua_pushinteger(luastate, 0);
242 lua_pushinteger(luastate, 0);
243 }
244 return 6;
245}
246
247static int LuaFlowGet(lua_State *luastate)
248{
249 Flow *f = LuaStateGetFlow(luastate);
250 if (f == NULL) {
251 LUA_ERROR("failed to get flow");
252 }
253
254 struct LuaFlow *s = (struct LuaFlow *)lua_newuserdata(luastate, sizeof(*s));
255 if (s == NULL) {
256 LUA_ERROR("failed to allocate userdata");
257 }
258 s->f = f;
259 luaL_getmetatable(luastate, suricata_flow);
260 lua_setmetatable(luastate, -2);
261 return 1;
262}
263
264static const luaL_Reg flowlib[] = {
265 // clang-format off
266 { "get", LuaFlowGet },
267 { NULL, NULL }
268 // clang-format on
269};
270
271static const luaL_Reg flowlib_meta[] = {
272 // clang-format off
273 { "id", LuaFlowId },
274 { "app_layer_proto", LuaFlowAppLayerProto },
275 { "has_alerts", LuaFlowHasAlerts },
276 { "stats", LuaFlowStats },
277 { "timestamps", LuaFlowTimestamps },
278 { "timestring_iso8601", LuaFlowTimestringIso8601 },
279 { "timestring_legacy", LuaFlowTimestringLegacy },
280 { "tuple", LuaFlowTuple },
281 { "__gc", LuaFlowGC },
282 { NULL, NULL }
283 // clang-format on
284};
285
287{
288 luaL_newmetatable(luastate, suricata_flow);
289 lua_pushvalue(luastate, -1);
290 lua_setfield(luastate, -2, "__index");
291 luaL_setfuncs(luastate, flowlib_meta, 0);
292
293 luaL_newlib(luastate, flowlib);
294 return 1;
295}
const char * AppProtoToString(AppProto alproto)
Maps the ALPROTO_*, to its string equivalent.
int FlowHasAlerts(const Flow *f)
Check if flow has alerts.
Definition flow.c:164
#define FLOW_IS_IPV6(f)
Definition flow.h:172
#define FLOW_IS_IPV4(f)
Definition flow.h:170
union FlowAddress_::@128 address
Flow data structure.
Definition flow.h:356
struct Flow_::@129::@135 icmp_s
AppProto alproto_ts
Definition flow.h:451
Port dp
Definition flow.h:372
AppProto alproto_tc
Definition flow.h:452
uint8_t proto
Definition flow.h:378
AppProto alproto_expect
Definition flow.h:459
AppProto alproto
application level protocol
Definition flow.h:450
uint64_t tosrcbytecnt
Definition flow.h:498
AppProto alproto_orig
Definition flow.h:456
uint64_t todstbytecnt
Definition flow.h:497
SCTime_t lastts
Definition flow.h:410
uint8_t code
Definition flow.h:364
uint32_t todstpktcnt
Definition flow.h:495
FlowAddress src
Definition flow.h:359
Port sp
Definition flow.h:361
FlowAddress dst
Definition flow.h:359
uint32_t tosrcpktcnt
Definition flow.h:496
uint8_t type
Definition flow.h:363
SCTime_t startts
Definition flow.h:493
struct lua_State lua_State
#define SCLogDebug(...)
Definition util-debug.h:275
#define LUA_ERROR(msg)
const char lua_ext_key_f[]
int LuaLoadFlowLib(lua_State *luastate)
Flow * LuaStateGetFlow(lua_State *luastate)
get flow pointer from lua state
Definition util-lua.c:161
const char * PrintInet(int af, const void *src, char *dst, socklen_t size)
Definition util-print.c:231
void CreateTimeString(const SCTime_t ts, char *str, size_t size)
Definition util-time.c:272
void CreateIsoTimeString(const SCTime_t ts, char *str, size_t size)
Definition util-time.c:209
#define SCTIME_SECS(t)
Definition util-time.h:57
#define SCTIME_USECS(t)
Definition util-time.h:56