• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 23374838686

21 Mar 2026 07:29AM UTC coverage: 59.341% (-20.0%) from 79.315%
23374838686

Pull #15075

github

web-flow
Merge 90b4e834f into 6587e363a
Pull Request #15075: Stack 8001 v16.4

38 of 70 new or added lines in 10 files covered. (54.29%)

34165 existing lines in 563 files now uncovered.

119621 of 201584 relevant lines covered (59.34%)

650666.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/util-lua-flowlib.c
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)
UNCOV
45
{
×
UNCOV
46
    SCLogDebug("gc:start");
×
UNCOV
47
    struct LuaFlow *s = (struct LuaFlow *)lua_touserdata(luastate, 1);
×
UNCOV
48
    if (s != NULL) {
×
UNCOV
49
        SCLogDebug("flow %p", s->f);
×
UNCOV
50
        s->f = NULL;
×
UNCOV
51
    }
×
UNCOV
52
    SCLogDebug("gc:done");
×
UNCOV
53
    return 0;
×
UNCOV
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)
UNCOV
64
{
×
UNCOV
65
    struct LuaFlow *s = (struct LuaFlow *)lua_touserdata(luastate, 1);
×
UNCOV
66
    if (s == NULL || s->f == NULL) {
×
67
        LUA_ERROR("failed to get flow");
×
68
    }
×
69

UNCOV
70
    Flow *f = s->f;
×
71

UNCOV
72
    int64_t id = (int64_t)FlowGetId(f);
×
UNCOV
73
    lua_pushinteger(luastate, id);
×
UNCOV
74
    return 1;
×
UNCOV
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)
UNCOV
87
{
×
UNCOV
88
    struct LuaFlow *s = (struct LuaFlow *)lua_touserdata(luastate, 1);
×
UNCOV
89
    if (s == NULL || s->f == NULL) {
×
90
        LUA_ERROR("failed to get flow");
×
91
    }
×
92

UNCOV
93
    Flow *f = s->f;
×
UNCOV
94
    lua_pushstring(luastate, AppProtoToString(f->alproto));
×
UNCOV
95
    lua_pushstring(luastate, AppProtoToString(f->alproto_ts));
×
UNCOV
96
    lua_pushstring(luastate, AppProtoToString(f->alproto_tc));
×
UNCOV
97
    lua_pushstring(luastate, AppProtoToString(f->alproto_orig));
×
UNCOV
98
    lua_pushstring(luastate, AppProtoToString(f->alproto_expect));
×
UNCOV
99
    return 5;
×
UNCOV
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)
UNCOV
110
{
×
UNCOV
111
    struct LuaFlow *s = (struct LuaFlow *)lua_touserdata(luastate, 1);
×
UNCOV
112
    if (s == NULL || s->f == NULL) {
×
113
        LUA_ERROR("failed to get flow");
×
114
    }
×
115

UNCOV
116
    Flow *f = s->f;
×
UNCOV
117
    lua_pushboolean(luastate, FlowHasAlerts(f));
×
UNCOV
118
    return 1;
×
UNCOV
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)
UNCOV
129
{
×
UNCOV
130
    struct LuaFlow *s = (struct LuaFlow *)lua_touserdata(luastate, 1);
×
UNCOV
131
    if (s == NULL || s->f == NULL) {
×
132
        LUA_ERROR("failed to get flow");
×
133
    }
×
134

UNCOV
135
    Flow *f = s->f;
×
UNCOV
136
    lua_pushinteger(luastate, f->todstpktcnt);
×
UNCOV
137
    lua_pushinteger(luastate, f->todstbytecnt);
×
UNCOV
138
    lua_pushinteger(luastate, f->tosrcpktcnt);
×
UNCOV
139
    lua_pushinteger(luastate, f->tosrcbytecnt);
×
UNCOV
140
    return 4;
×
UNCOV
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)
UNCOV
152
{
×
UNCOV
153
    struct LuaFlow *s = (struct LuaFlow *)lua_touserdata(luastate, 1);
×
UNCOV
154
    if (s == NULL || s->f == NULL) {
×
155
        LUA_ERROR("failed to get flow");
×
156
    }
×
157

UNCOV
158
    Flow *f = s->f;
×
UNCOV
159
    lua_pushnumber(luastate, (double)SCTIME_SECS(f->startts));
×
UNCOV
160
    lua_pushnumber(luastate, (double)SCTIME_SECS(f->lastts));
×
UNCOV
161
    lua_pushnumber(luastate, (double)SCTIME_USECS(f->startts));
×
UNCOV
162
    lua_pushnumber(luastate, (double)SCTIME_USECS(f->lastts));
×
UNCOV
163
    return 4;
×
UNCOV
164
}
×
165

166
static int LuaFlowTimestringIso8601(lua_State *luastate)
UNCOV
167
{
×
UNCOV
168
    struct LuaFlow *s = (struct LuaFlow *)lua_touserdata(luastate, 1);
×
UNCOV
169
    if (s == NULL || s->f == NULL) {
×
170
        LUA_ERROR("failed to get flow");
×
171
    }
×
172

UNCOV
173
    Flow *f = s->f;
×
UNCOV
174
    char timebuf[64];
×
UNCOV
175
    CreateIsoTimeString(f->startts, timebuf, sizeof(timebuf));
×
UNCOV
176
    lua_pushstring(luastate, timebuf);
×
UNCOV
177
    return 1;
×
UNCOV
178
}
×
179

180
/** \internal
181
 *  \brief legacy format as used by fast.log, http.log, etc.
182
 */
183
static int LuaFlowTimestringLegacy(lua_State *luastate)
UNCOV
184
{
×
UNCOV
185
    struct LuaFlow *s = (struct LuaFlow *)lua_touserdata(luastate, 1);
×
UNCOV
186
    if (s == NULL || s->f == NULL) {
×
187
        LUA_ERROR("failed to get flow");
×
188
    }
×
189

UNCOV
190
    Flow *f = s->f;
×
UNCOV
191
    char timebuf[64];
×
UNCOV
192
    CreateTimeString(f->startts, timebuf, sizeof(timebuf));
×
UNCOV
193
    lua_pushstring(luastate, timebuf);
×
UNCOV
194
    return 1;
×
UNCOV
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)
UNCOV
206
{
×
UNCOV
207
    struct LuaFlow *s = (struct LuaFlow *)lua_touserdata(luastate, 1);
×
UNCOV
208
    if (s == NULL || s->f == NULL) {
×
209
        LUA_ERROR("failed to get flow");
×
210
    }
×
UNCOV
211
    Flow *f = s->f;
×
UNCOV
212
    int ipver = 0;
×
UNCOV
213
    if (FLOW_IS_IPV4(f)) {
×
UNCOV
214
        ipver = 4;
×
UNCOV
215
    } else if (FLOW_IS_IPV6(f)) {
×
216
        ipver = 6;
×
217
    }
×
UNCOV
218
    lua_pushinteger(luastate, ipver);
×
UNCOV
219
    if (ipver == 0)
×
220
        return 1;
×
221

UNCOV
222
    char srcip[46] = "", dstip[46] = "";
×
UNCOV
223
    if (FLOW_IS_IPV4(f)) {
×
UNCOV
224
        PrintInet(AF_INET, (const void *)&(f->src.addr_data32[0]), srcip, sizeof(srcip));
×
UNCOV
225
        PrintInet(AF_INET, (const void *)&(f->dst.addr_data32[0]), dstip, sizeof(dstip));
×
UNCOV
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

UNCOV
231
    lua_pushstring(luastate, srcip);
×
UNCOV
232
    lua_pushstring(luastate, dstip);
×
233

234
    /* proto and ports (or type/ code) */
UNCOV
235
    lua_pushinteger(luastate, f->proto);
×
UNCOV
236
    if (f->proto == IPPROTO_TCP || f->proto == IPPROTO_UDP) {
×
UNCOV
237
        lua_pushinteger(luastate, f->sp);
×
UNCOV
238
        lua_pushinteger(luastate, f->dp);
×
UNCOV
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);
×
UNCOV
242
    } else {
×
UNCOV
243
        lua_pushinteger(luastate, 0);
×
UNCOV
244
        lua_pushinteger(luastate, 0);
×
UNCOV
245
    }
×
UNCOV
246
    return 6;
×
UNCOV
247
}
×
248

249
static int LuaFlowGet(lua_State *luastate)
UNCOV
250
{
×
UNCOV
251
    Flow *f = LuaStateGetFlow(luastate);
×
UNCOV
252
    if (f == NULL) {
×
253
        LUA_ERROR("failed to get flow");
×
254
    }
×
255

UNCOV
256
    struct LuaFlow *s = (struct LuaFlow *)lua_newuserdata(luastate, sizeof(*s));
×
UNCOV
257
    if (s == NULL) {
×
258
        LUA_ERROR("failed to allocate userdata");
×
259
    }
×
UNCOV
260
    s->f = f;
×
UNCOV
261
    luaL_getmetatable(luastate, suricata_flow);
×
UNCOV
262
    lua_setmetatable(luastate, -2);
×
UNCOV
263
    return 1;
×
UNCOV
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)
UNCOV
289
{
×
UNCOV
290
    luaL_newmetatable(luastate, suricata_flow);
×
UNCOV
291
    lua_pushvalue(luastate, -1);
×
UNCOV
292
    lua_setfield(luastate, -2, "__index");
×
UNCOV
293
    luaL_setfuncs(luastate, flowlib_meta, 0);
×
294

UNCOV
295
    luaL_newlib(luastate, flowlib);
×
UNCOV
296
    return 1;
×
UNCOV
297
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc