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 */
37 extern const char lua_ext_key_f[];
38 static const char suricata_flow[] = "suricata:flow";
39 
40 struct LuaFlow {
41  Flow *f;
42 };
43 
44 static 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  */
61 static 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 = 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  */
84 static 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  */
107 static 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  */
126 static 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  */
149 static 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 
164 static 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  */
181 static 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  */
203 static 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 
247 static 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 
264 static const luaL_Reg flowlib[] = {
265  // clang-format off
266  { "get", LuaFlowGet },
267  { NULL, NULL }
268  // clang-format on
269 };
270 
271 static 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 
286 int LuaLoadFlowLib(lua_State *luastate)
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 }
LUA_ERROR
#define LUA_ERROR(msg)
Definition: util-lua-common.h:41
FLOW_IS_IPV6
#define FLOW_IS_IPV6(f)
Definition: flow.h:170
util-lua-common.h
CreateIsoTimeString
void CreateIsoTimeString(const SCTime_t ts, char *str, size_t size)
Definition: util-time.c:209
Flow_::startts
SCTime_t startts
Definition: flow.h:491
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
Flow_::proto
uint8_t proto
Definition: flow.h:376
util-lua.h
Flow_
Flow data structure.
Definition: flow.h:354
AppProtoToString
const char * AppProtoToString(AppProto alproto)
Maps the ALPROTO_*, to its string equivalent.
Definition: app-layer-protos.c:40
Flow_::alproto_orig
AppProto alproto_orig
Definition: flow.h:454
Flow_::dp
Port dp
Definition: flow.h:370
lua_ext_key_f
const char lua_ext_key_f[]
lua_State
struct lua_State lua_State
Definition: suricata-common.h:515
Flow_::tosrcbytecnt
uint64_t tosrcbytecnt
Definition: flow.h:496
Flow_::dst
FlowAddress dst
Definition: flow.h:357
util-debug.h
Flow_::todstpktcnt
uint32_t todstpktcnt
Definition: flow.h:493
Flow_::lastts
SCTime_t lastts
Definition: flow.h:408
util-print.h
PrintInet
const char * PrintInet(int af, const void *src, char *dst, socklen_t size)
Definition: util-print.c:231
Flow_::todstbytecnt
uint64_t todstbytecnt
Definition: flow.h:495
FLOW_IS_IPV4
#define FLOW_IS_IPV4(f)
Definition: flow.h:168
util-lua-flowlib.h
Flow_::alproto_expect
AppProto alproto_expect
Definition: flow.h:457
LuaFlow::f
Flow * f
Definition: util-lua-flowlib.c:41
LuaFlow
Definition: util-lua-flowlib.c:40
Flow_::src
FlowAddress src
Definition: flow.h:357
LuaLoadFlowLib
int LuaLoadFlowLib(lua_State *luastate)
Definition: util-lua-flowlib.c:286
suricata-common.h
SCTIME_SECS
#define SCTIME_SECS(t)
Definition: util-time.h:57
Flow_::icmp_s
struct Flow_::@112::@118 icmp_s
Flow_::alproto_ts
AppProto alproto_ts
Definition: flow.h:449
FlowAddress_::address
union FlowAddress_::@111 address
LuaStateGetFlow
Flow * LuaStateGetFlow(lua_State *luastate)
get flow pointer from lua state
Definition: util-lua.c:161
app-layer-protos.h
FlowHasAlerts
int FlowHasAlerts(const Flow *f)
Check if flow has alerts.
Definition: flow.c:162
Flow_::sp
Port sp
Definition: flow.h:359
Flow_::alproto_tc
AppProto alproto_tc
Definition: flow.h:450
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:448
Flow_::tosrcpktcnt
uint32_t tosrcpktcnt
Definition: flow.h:494
CreateTimeString
void CreateTimeString(const SCTime_t ts, char *str, size_t size)
Definition: util-time.c:272
SCTIME_USECS
#define SCTIME_USECS(t)
Definition: util-time.h:56