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