-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lua packetlib/v2 #12512
Closed
+300
−174
Closed
Lua packetlib/v2 #12512
Changes from 1 commit
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
f1775e9
detect/lua: remove unused tls flag
victorjulien a168a26
detect/lua: minor code cleanup
victorjulien 892cac2
lua: add initial suricata.packet lib
victorjulien 307e876
lua: remove old lua payload/packet calls
victorjulien 5f8158e
detect/lua: register built-in libs also for open setup
victorjulien File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
lua: add initial suricata.packet lib
Example: ``` local packet = require "suricata.packet" function init (args) local needs = {} return needs end function match (args) p = packet.get() payload = p:payload() ts = p:timestring() for line in payload:gmatch("([^\r\n]*)[\r\n]+") do if line == "GET /index.html HTTP/1.0" then ipver, srcip, dstip, proto, sp, dp = p:tuple() SCLogNotice(string.format("%s %s->%s %d->%d (pcap_cnt:%d) match! %s", ts, srcip, dstip, sp, dp, p:pcap_cnt(), line)); return 1 end end return 0 end ``` Methods: `get` creates the packet object. `payload` returns the packet payload as a buffer `packet` returns the whole packet (includes headers) `pcap_cnt` returns the `pcap_cnt` (pcap file mode only) `tuple` returns various fields: srcip, dstip, proto, sp, dp `timestamp` returns time as 2 numbers: seconds and microseconds `timestring` returns a timestamp as a string Ticket: #7488.
commit 892cac2490f2082ebdf3bc131b9f36ba2e9929f9
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,265 @@ | ||
/* Copyright (C) 2025 Open Information Security Foundation | ||
* | ||
* You can copy, redistribute or modify this Program under the terms of | ||
* the GNU General Public License version 2 as published by the Free | ||
* Software Foundation. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* version 2 along with this program; if not, write to the Free Software | ||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
* 02110-1301, USA. | ||
*/ | ||
|
||
/** | ||
* \file | ||
* | ||
* Packet API for Lua. | ||
* | ||
* local packet = require("suricata.packet") | ||
*/ | ||
|
||
#include "suricata-common.h" | ||
|
||
#include "util-lua-packetlib.h" | ||
|
||
#include "app-layer-protos.h" /* Required by util-lua-common. */ | ||
#include "util-lua-common.h" | ||
#include "util-lua.h" | ||
#include "util-debug.h" | ||
#include "util-print.h" | ||
|
||
/* key for p (packet) pointer */ | ||
extern const char lua_ext_key_p[]; | ||
static const char suricata_packet[] = "suricata:packet"; | ||
|
||
struct LuaPacket { | ||
Packet *p; | ||
}; | ||
|
||
static int LuaPacketGC(lua_State *luastate) | ||
{ | ||
SCLogDebug("gc:start"); | ||
struct LuaPacket *s = (struct LuaPacket *)lua_touserdata(luastate, 1); | ||
SCLogDebug("packet %p", s->p); | ||
s->p = NULL; | ||
SCLogDebug("gc:done"); | ||
return 0; | ||
} | ||
|
||
static int LuaPacketPayload(lua_State *luastate) | ||
{ | ||
struct LuaPacket *s = (struct LuaPacket *)lua_touserdata(luastate, 1); | ||
if (s == NULL || s->p == NULL) { | ||
LUA_ERROR("failed to get packet"); | ||
} | ||
|
||
LuaPushStringBuffer(luastate, (const uint8_t *)s->p->payload, (size_t)s->p->payload_len); | ||
return 1; | ||
} | ||
|
||
static int LuaPacketPacket(lua_State *luastate) | ||
{ | ||
struct LuaPacket *s = (struct LuaPacket *)lua_touserdata(luastate, 1); | ||
if (s == NULL || s->p == NULL) { | ||
LUA_ERROR("failed to get packet"); | ||
} | ||
|
||
LuaPushStringBuffer(luastate, (const uint8_t *)GET_PKT_DATA(s->p), (size_t)GET_PKT_LEN(s->p)); | ||
return 1; | ||
} | ||
|
||
static int LuaPacketPcapCnt(lua_State *luastate) | ||
{ | ||
struct LuaPacket *s = (struct LuaPacket *)lua_touserdata(luastate, 1); | ||
if (s == NULL || s->p == NULL) { | ||
LUA_ERROR("failed to get packet"); | ||
} | ||
|
||
lua_pushinteger(luastate, s->p->pcap_cnt); | ||
return 1; | ||
} | ||
|
||
static int LuaPacketTimestring(lua_State *luastate) | ||
{ | ||
struct LuaPacket *s = (struct LuaPacket *)lua_touserdata(luastate, 1); | ||
if (s == NULL || s->p == NULL) { | ||
LUA_ERROR("failed to get packet"); | ||
} | ||
|
||
char timebuf[64]; | ||
CreateTimeString(s->p->ts, timebuf, sizeof(timebuf)); | ||
lua_pushstring(luastate, timebuf); | ||
return 1; | ||
} | ||
|
||
static int LuaPacketTimestamp(lua_State *luastate) | ||
{ | ||
struct LuaPacket *s = (struct LuaPacket *)lua_touserdata(luastate, 1); | ||
if (s == NULL || s->p == NULL) { | ||
LUA_ERROR("failed to get packet"); | ||
} | ||
|
||
lua_pushnumber(luastate, (double)SCTIME_SECS(s->p->ts)); | ||
lua_pushnumber(luastate, (double)SCTIME_USECS(s->p->ts)); | ||
return 2; | ||
} | ||
|
||
/** \internal | ||
* \brief fill lua stack with header info | ||
* \param luastate the lua state | ||
* \retval cnt number of data items placed on the stack | ||
* | ||
* Places: ipver (number), src ip (string), dst ip (string), protocol (number), | ||
* sp or icmp type (number), dp or icmp code (number). | ||
*/ | ||
static int LuaPacketTuple(lua_State *luastate) | ||
{ | ||
struct LuaPacket *s = (struct LuaPacket *)lua_touserdata(luastate, 1); | ||
if (s == NULL || s->p == NULL) { | ||
LUA_ERROR("failed to get packet"); | ||
} | ||
Packet *p = s->p; | ||
|
||
int ipver = 0; | ||
if (PacketIsIPv4(p)) { | ||
ipver = 4; | ||
} else if (PacketIsIPv6(p)) { | ||
ipver = 6; | ||
} | ||
lua_pushinteger(luastate, ipver); | ||
if (ipver == 0) | ||
return 1; | ||
|
||
char srcip[46] = "", dstip[46] = ""; | ||
if (PacketIsIPv4(p)) { | ||
PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip)); | ||
PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip)); | ||
} else if (PacketIsIPv6(p)) { | ||
PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); | ||
PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); | ||
} | ||
|
||
lua_pushstring(luastate, srcip); | ||
lua_pushstring(luastate, dstip); | ||
|
||
/* proto and ports (or type/code) */ | ||
lua_pushinteger(luastate, p->proto); | ||
if (p->proto == IPPROTO_TCP || p->proto == IPPROTO_UDP) { | ||
lua_pushinteger(luastate, p->sp); | ||
lua_pushinteger(luastate, p->dp); | ||
|
||
} else if (p->proto == IPPROTO_ICMP || p->proto == IPPROTO_ICMPV6) { | ||
lua_pushinteger(luastate, p->icmp_s.type); | ||
lua_pushinteger(luastate, p->icmp_s.code); | ||
} else { | ||
lua_pushinteger(luastate, 0); | ||
lua_pushinteger(luastate, 0); | ||
} | ||
|
||
return 6; | ||
} | ||
|
||
/** \internal | ||
* \brief get tcp/udp/sctp source port | ||
* \param luastate the lua state | ||
*/ | ||
static int LuaPacketSport(lua_State *luastate) | ||
{ | ||
struct LuaPacket *s = (struct LuaPacket *)lua_touserdata(luastate, 1); | ||
if (s == NULL || s->p == NULL) { | ||
LUA_ERROR("failed to get packet"); | ||
} | ||
Packet *p = s->p; | ||
|
||
switch (p->proto) { | ||
case IPPROTO_TCP: | ||
case IPPROTO_UDP: | ||
case IPPROTO_SCTP: | ||
lua_pushinteger(luastate, p->sp); | ||
break; | ||
default: | ||
LUA_ERROR("sp only available for tcp, udp and sctp"); | ||
} | ||
|
||
return 1; | ||
} | ||
|
||
/** \internal | ||
* \brief get tcp/udp/sctp dest port | ||
* \param luastate the lua state | ||
*/ | ||
static int LuaPacketDport(lua_State *luastate) | ||
{ | ||
struct LuaPacket *s = (struct LuaPacket *)lua_touserdata(luastate, 1); | ||
if (s == NULL || s->p == NULL) { | ||
LUA_ERROR("failed to get packet"); | ||
} | ||
Packet *p = s->p; | ||
|
||
switch (p->proto) { | ||
case IPPROTO_TCP: | ||
case IPPROTO_UDP: | ||
case IPPROTO_SCTP: | ||
lua_pushinteger(luastate, p->dp); | ||
break; | ||
default: | ||
LUA_ERROR("dp only available for tcp, udp and sctp"); | ||
} | ||
|
||
return 1; | ||
} | ||
|
||
static int LuaPacketGet(lua_State *luastate) | ||
{ | ||
Packet *p = LuaStateGetPacket(luastate); | ||
if (p == NULL) { | ||
LUA_ERROR("failed to get packet"); | ||
} | ||
|
||
struct LuaPacket *s = (struct LuaPacket *)lua_newuserdata(luastate, sizeof(*s)); | ||
if (s == NULL) { | ||
LUA_ERROR("failed to get userdata"); | ||
} | ||
s->p = p; | ||
luaL_getmetatable(luastate, suricata_packet); | ||
lua_setmetatable(luastate, -2); | ||
return 1; | ||
} | ||
|
||
static const luaL_Reg packetlib[] = { | ||
// clang-format off | ||
{ "get", LuaPacketGet }, | ||
{ NULL, NULL } | ||
// clang-format on | ||
}; | ||
|
||
static const luaL_Reg packetlib_meta[] = { | ||
// clang-format off | ||
{ "packet", LuaPacketPacket }, | ||
{ "payload", LuaPacketPayload }, | ||
{ "pcap_cnt", LuaPacketPcapCnt }, | ||
{ "timestring", LuaPacketTimestring }, | ||
{ "timestamp", LuaPacketTimestamp }, | ||
{ "tuple", LuaPacketTuple }, | ||
{ "sp", LuaPacketSport }, | ||
{ "dp", LuaPacketDport }, | ||
{ "__gc", LuaPacketGC }, | ||
{ NULL, NULL } | ||
// clang-format on | ||
}; | ||
Comment on lines
+234
to
+254
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Otherwise API looks OK to me. Time for docs :) |
||
|
||
int LuaLoadPacketLib(lua_State *luastate) | ||
{ | ||
luaL_newmetatable(luastate, suricata_packet); | ||
lua_pushvalue(luastate, -1); | ||
lua_setfield(luastate, -2, "__index"); | ||
luaL_setfuncs(luastate, packetlib_meta, 0); | ||
|
||
luaL_newlib(luastate, packetlib); | ||
return 1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* Copyright (C) 2025 Open Information Security Foundation | ||
* | ||
* You can copy, redistribute or modify this Program under the terms of | ||
* the GNU General Public License version 2 as published by the Free | ||
* Software Foundation. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* version 2 along with this program; if not, write to the Free Software | ||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
* 02110-1301, USA. | ||
*/ | ||
|
||
#ifndef SURICATA_UTIL_LUA_PACKET_H | ||
#define SURICATA_UTIL_LUA_PACKET_H | ||
|
||
#include "lua.h" | ||
|
||
int LuaLoadPacketLib(lua_State *luastate); | ||
|
||
#endif /* SURICATA_UTIL_LUA_DATASET_H */ |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think for a new API it would be really nice to generate a stanard timestring.. So instead of
we should do:
If needed, add a
_legacy
variant for the old one. Ortimestamp_rfc3339
for this new one, and some other specifier for the legacy format?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm open to suggestions for how to name the current output form I did (which is the common
CreateTimeString
method), but not interested at this point to explore crafting a new format. That can be a follow up ticket. It shouldn't block moving ahead with this I think.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leave as-is, document as "Suricata time string" or something along those lines with not about time zone.
timestring_rfc3339
can come later.