Coverage Report

Created: 2026-11-12 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata/src/util-lua-packetlib.c
Line
Count
Source
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
 * Packet API for Lua.
22
 *
23
 * local packet = require("suricata.packet")
24
 */
25
26
#include "suricata-common.h"
27
28
#include "util-lua-packetlib.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
static const char suricata_packet[] = "suricata:packet";
37
38
/* no stored pointer: the accessors act on the packet the state is
39
 * running on (LuaStateGetPacket), so a retained handle can never
40
 * dangle */
41
struct LuaPacket {
42
};
43
44
static int LuaPacketPayload(lua_State *luastate)
45
0
{
46
0
    SCLuaCheckUserData(luastate, 1, suricata_packet, SCLUA_TUD_PACKET);
47
0
    Packet *p = LuaStateGetPacket(luastate);
48
0
    if (p == NULL) {
49
0
        LUA_ERROR("failed to get packet");
50
0
    }
51
52
0
    LuaPushStringBuffer(luastate, (const uint8_t *)p->payload, (size_t)p->payload_len);
53
0
    return 1;
54
0
}
55
56
static int LuaPacketPacket(lua_State *luastate)
57
0
{
58
0
    SCLuaCheckUserData(luastate, 1, suricata_packet, SCLUA_TUD_PACKET);
59
0
    Packet *p = LuaStateGetPacket(luastate);
60
0
    if (p == NULL) {
61
0
        LUA_ERROR("failed to get packet");
62
0
    }
63
64
0
    LuaPushStringBuffer(luastate, (const uint8_t *)GET_PKT_DATA(p), (size_t)GET_PKT_LEN(p));
65
0
    return 1;
66
0
}
67
68
static int LuaPacketPcapCnt(lua_State *luastate)
69
0
{
70
0
    SCLuaCheckUserData(luastate, 1, suricata_packet, SCLUA_TUD_PACKET);
71
0
    Packet *p = LuaStateGetPacket(luastate);
72
0
    if (p == NULL) {
73
0
        LUA_ERROR("failed to get packet");
74
0
    }
75
76
0
    lua_pushinteger(luastate, PcapPacketCntGet(p));
77
0
    return 1;
78
0
}
79
80
/** \internal
81
 *  \brief legacy format as used by fast.log, etc.
82
 */
83
static int LuaPacketTimestringLegacy(lua_State *luastate)
84
0
{
85
0
    SCLuaCheckUserData(luastate, 1, suricata_packet, SCLUA_TUD_PACKET);
86
0
    Packet *p = LuaStateGetPacket(luastate);
87
0
    if (p == NULL) {
88
0
        LUA_ERROR("failed to get packet");
89
0
    }
90
91
0
    char timebuf[64];
92
0
    CreateTimeString(p->ts, timebuf, sizeof(timebuf));
93
0
    lua_pushstring(luastate, timebuf);
94
0
    return 1;
95
0
}
96
97
static int LuaPacketTimestringIso8601(lua_State *luastate)
98
0
{
99
0
    SCLuaCheckUserData(luastate, 1, suricata_packet, SCLUA_TUD_PACKET);
100
0
    Packet *p = LuaStateGetPacket(luastate);
101
0
    if (p == NULL) {
102
0
        LUA_ERROR("failed to get packet");
103
0
    }
104
105
0
    char timebuf[64];
106
0
    CreateIsoTimeString(p->ts, timebuf, sizeof(timebuf));
107
0
    lua_pushstring(luastate, timebuf);
108
0
    return 1;
109
0
}
110
111
static int LuaPacketTimestamp(lua_State *luastate)
112
0
{
113
0
    SCLuaCheckUserData(luastate, 1, suricata_packet, SCLUA_TUD_PACKET);
114
0
    Packet *p = LuaStateGetPacket(luastate);
115
0
    if (p == NULL) {
116
0
        LUA_ERROR("failed to get packet");
117
0
    }
118
119
0
    lua_pushnumber(luastate, (double)SCTIME_SECS(p->ts));
120
0
    lua_pushnumber(luastate, (double)SCTIME_USECS(p->ts));
121
0
    return 2;
122
0
}
123
124
/** \internal
125
 *  \brief fill lua stack with header info
126
 *  \param luastate the lua state
127
 *  \retval cnt number of data items placed on the stack
128
 *
129
 *  Places: ipver (number), src ip (string), dst ip (string), protocol (number),
130
 *          sp or icmp type (number), dp or icmp code (number).
131
 */
132
static int LuaPacketTuple(lua_State *luastate)
133
0
{
134
0
    SCLuaCheckUserData(luastate, 1, suricata_packet, SCLUA_TUD_PACKET);
135
0
    Packet *p = LuaStateGetPacket(luastate);
136
0
    if (p == NULL) {
137
0
        LUA_ERROR("failed to get packet");
138
0
    }
139
140
0
    int ipver = 0;
141
0
    if (PacketIsIPv4(p)) {
142
0
        ipver = 4;
143
0
    } else if (PacketIsIPv6(p)) {
144
0
        ipver = 6;
145
0
    }
146
0
    lua_pushinteger(luastate, ipver);
147
0
    if (ipver == 0)
148
0
        return 1;
149
150
0
    char srcip[46] = "", dstip[46] = "";
151
0
    if (PacketIsIPv4(p)) {
152
0
        PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip));
153
0
        PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip));
154
0
    } else if (PacketIsIPv6(p)) {
155
0
        PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip));
156
0
        PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip));
157
0
    }
158
159
0
    lua_pushstring(luastate, srcip);
160
0
    lua_pushstring(luastate, dstip);
161
162
    /* proto and ports (or type/code) */
163
0
    lua_pushinteger(luastate, p->proto);
164
0
    if (p->proto == IPPROTO_TCP || p->proto == IPPROTO_UDP) {
165
0
        lua_pushinteger(luastate, p->sp);
166
0
        lua_pushinteger(luastate, p->dp);
167
168
0
    } else if (p->proto == IPPROTO_ICMP || p->proto == IPPROTO_ICMPV6) {
169
0
        lua_pushinteger(luastate, p->icmp_s.type);
170
0
        lua_pushinteger(luastate, p->icmp_s.code);
171
0
    } else {
172
0
        lua_pushinteger(luastate, 0);
173
0
        lua_pushinteger(luastate, 0);
174
0
    }
175
176
0
    return 6;
177
0
}
178
179
/** \internal
180
 *  \brief get tcp/udp/sctp source port
181
 *  \param luastate the lua state
182
 */
183
static int LuaPacketSport(lua_State *luastate)
184
0
{
185
0
    SCLuaCheckUserData(luastate, 1, suricata_packet, SCLUA_TUD_PACKET);
186
0
    Packet *p = LuaStateGetPacket(luastate);
187
0
    if (p == NULL) {
188
0
        LUA_ERROR("failed to get packet");
189
0
    }
190
191
0
    switch (p->proto) {
192
0
        case IPPROTO_TCP:
193
0
        case IPPROTO_UDP:
194
0
        case IPPROTO_SCTP:
195
0
            lua_pushinteger(luastate, p->sp);
196
0
            break;
197
0
        default:
198
0
            LUA_ERROR("sp only available for tcp, udp and sctp");
199
0
    }
200
201
0
    return 1;
202
0
}
203
204
/** \internal
205
 *  \brief get tcp/udp/sctp dest port
206
 *  \param luastate the lua state
207
 */
208
static int LuaPacketDport(lua_State *luastate)
209
0
{
210
0
    SCLuaCheckUserData(luastate, 1, suricata_packet, SCLUA_TUD_PACKET);
211
0
    Packet *p = LuaStateGetPacket(luastate);
212
0
    if (p == NULL) {
213
0
        LUA_ERROR("failed to get packet");
214
0
    }
215
216
0
    switch (p->proto) {
217
0
        case IPPROTO_TCP:
218
0
        case IPPROTO_UDP:
219
0
        case IPPROTO_SCTP:
220
0
            lua_pushinteger(luastate, p->dp);
221
0
            break;
222
0
        default:
223
0
            LUA_ERROR("dp only available for tcp, udp and sctp");
224
0
    }
225
226
0
    return 1;
227
0
}
228
229
static int LuaPacketGet(lua_State *luastate)
230
0
{
231
0
    Packet *p = LuaStateGetPacket(luastate);
232
0
    if (p == NULL) {
233
0
        LUA_ERROR("failed to get packet");
234
0
    }
235
236
0
    struct LuaPacket *s = SCLuaNewUserData(luastate, SCLUA_TUD_PACKET, sizeof(*s));
237
0
    if (s == NULL) {
238
0
        LUA_ERROR("failed to get userdata");
239
0
    }
240
0
    luaL_getmetatable(luastate, suricata_packet);
241
0
    lua_setmetatable(luastate, -2);
242
0
    return 1;
243
0
}
244
245
static const luaL_Reg packetlib[] = {
246
    // clang-format off
247
    { "get", LuaPacketGet },
248
    { NULL, NULL }
249
    // clang-format on
250
};
251
252
static const luaL_Reg packetlib_meta[] = {
253
    // clang-format off
254
    { "packet", LuaPacketPacket },
255
    { "payload", LuaPacketPayload },
256
    { "pcap_cnt", LuaPacketPcapCnt },
257
    { "timestring_legacy", LuaPacketTimestringLegacy },
258
    { "timestring_iso8601", LuaPacketTimestringIso8601 },
259
    { "timestamp", LuaPacketTimestamp },
260
    { "tuple", LuaPacketTuple },
261
    { "sp", LuaPacketSport },
262
    { "dp", LuaPacketDport },
263
    { NULL, NULL }
264
    // clang-format on
265
};
266
267
int LuaLoadPacketLib(lua_State *luastate)
268
0
{
269
0
    luaL_newmetatable(luastate, suricata_packet);
270
0
    lua_pushvalue(luastate, -1);
271
0
    lua_setfield(luastate, -2, "__index");
272
0
    luaL_setfuncs(luastate, packetlib_meta, 0);
273
274
0
    luaL_newlib(luastate, packetlib);
275
0
    return 1;
276
0
}