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