Skip to content
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

next/716/20250212/v1 #12569

Merged
merged 19 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@
AC_CHECK_HEADERS([mach/mach.h])
AC_CHECK_HEADERS([stdatomic.h])
AC_CHECK_HEADERS([sys/queue.h])
AC_CHECK_HEADERS([mm_malloc.h])

AC_CHECK_HEADERS([sys/socket.h net/if.h sys/mman.h linux/if_arp.h], [], [],
[[#ifdef HAVE_SYS_SOCKET_H
Expand Down Expand Up @@ -2489,6 +2490,7 @@ AC_SUBST(e_logcertsdir)
AC_SUBST(e_sysconfdir)
AC_DEFINE_UNQUOTED([CONFIG_DIR],["$e_sysconfdir"],[Our CONFIG_DIR])
AC_SUBST(e_localstatedir)
AC_DEFINE_UNQUOTED([LOCAL_STATE_DIR],["$localstatedir"],[Our LOCAL_STATE_DIR])
AC_SUBST(e_datadir)
AC_DEFINE_UNQUOTED([DATA_DIR],["$e_datadir"],[Our DATA_DIR])
AC_SUBST(e_magic_file)
Expand Down
1 change: 1 addition & 0 deletions doc/userguide/lua/libs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ environment without access to additional modules.
.. toctree::

hashlib
packetlib
177 changes: 177 additions & 0 deletions doc/userguide/lua/libs/packetlib.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
Packet
------

Packets are exposed to Lua scripts with ``suricata.packet``
library. For example::

local packet = require("suricata.packet")

Initialization
~~~~~~~~~~~~~~

``get``
^^^^^^^

Init the packet for use in the script. The packet is the current packet the engine is processing.

::

p = packet.get()


Time
~~~~

``timestamp``
^^^^^^^^^^^^^

Get packet timestamp as 2 numbers: seconds & microseconds elapsed since
1970-01-01 00:00:00 UTC.

::

p = packet.get()
local sec, usec = p:timestamp()


``timestring_legacy``
^^^^^^^^^^^^^^^^^^^^^

Get packet timestamp as a string in the format: `11/24/2009-18:57:25.179869`.
This is the format used by `fast.log`, `http.log` and other legacy outputs.

::

p = packet.get()
print p:timestring_legacy()


``timestring_iso8601``
^^^^^^^^^^^^^^^^^^^^^^

Get packet timestamp as a string in the format: `2015-10-06T15:16:43.137833+0000`.
This is the format used by `eve`.

::

p = packet.get()
print p:timestring_iso8601()


Ports and Addresses
~~~~~~~~~~~~~~~~~~~

``tuple``
^^^^^^^^^

Using the `tuple` method the IP version (4 or 6), src IP and dest IP (as string), IP protocol (int) and ports (ints) are retrieved.

The protocol value comes from the IP header, see further https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml

::

p = packet.get()
ipver, srcip, dstip, proto, sp, dp = p:tuple()


If the protocol is ICMPv4 or ICMPv6, so when `proto == 1` or `proto == 58`, then the final two results are `icmp type` and `icmp code`.

::

p = packet.get()
ipver, srcip, dstip, proto, itype, icode = p:tuple()
if ipver == 6 and proto == 1 then
-- weird, ICMPv4 on IPv6
return 1
end


``sp``
^^^^^^

Get the packets TCP, UDP or SCTP source port as an int. Returns `nil` for other protocols.

::

p = packet.get()
source_port = p:sp()
if source_port == 31337 then
return 1
end


``dp``
^^^^^^

Get the packets TCP, UDP or SCTP destination port as an int. Returns `nil` for other protocols.

::

p = packet.get()
dest_port = p:dp()
-- not port 443
if dest_port ~= 443 then
return 1
end


Data
~~~~

``payload``
^^^^^^^^^^^

Packet payload.

::

payload = p:payload()


``packet``
^^^^^^^^^^

Entire packet, including headers for protocols like TCP, Ethernet, VLAN, etc.

::

raw_packet = p:packet()


Misc
~~~~

``pcap_cnt``
^^^^^^^^^^^^

The packet number when reading from a pcap file.

::

p = packet.get()
print p:pcap_cnt()


Example
~~~~~~~

Example `match` function that takes a packet, inspect the payload line by line and checks if it finds the HTTP request line.
If it is found, issue a notice log with packet details.

::

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
36 changes: 0 additions & 36 deletions doc/userguide/lua/lua-functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,42 +45,6 @@ Initialize with:
return needs
end

SCPacketTimestamp
~~~~~~~~~~~~~~~~~

Get packets timestamp as 2 numbers: seconds & microseconds elapsed since
1970-01-01 00:00:00 UTC.

::

function log(args)
local sec, usec = SCPacketTimestamp()
end

SCPacketTimeString
~~~~~~~~~~~~~~~~~~

Use ``SCPacketTimeString`` to get the packet's time string in the format:
11/24/2009-18:57:25.179869

::

function log(args)
ts = SCPacketTimeString()

SCPacketTuple
~~~~~~~~~~~~~

::

ipver, srcip, dstip, proto, sp, dp = SCPacketTuple()

SCPacketPayload
~~~~~~~~~~~~~~~

::

p = SCPacketPayload()

flow
----
Expand Down
4 changes: 3 additions & 1 deletion src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,7 @@ noinst_HEADERS = \
util-lua-hassh.h \
util-lua-http.h \
util-lua-ja3.h \
util-lua-packetlib.h \
util-lua-sandbox.h \
util-lua-smtp.h \
util-lua-ssh.h \
Expand Down Expand Up @@ -1075,6 +1076,7 @@ libsuricata_c_a_SOURCES = \
util-lua-hassh.c \
util-lua-http.c \
util-lua-ja3.c \
util-lua-packetlib.c \
util-lua-sandbox.c \
util-lua-smtp.c \
util-lua-ssh.c \
Expand Down Expand Up @@ -1382,7 +1384,7 @@ endif

# default CFLAGS
AM_CFLAGS = ${OPTIMIZATION_CFLAGS} ${GCC_CFLAGS} ${CLANG_CFLAGS} \
${SECCFLAGS} ${PCAP_CFLAGS} -DLOCAL_STATE_DIR=\"$(localstatedir)\" \
${SECCFLAGS} ${PCAP_CFLAGS} \
-Wall -Wno-unused-parameter -Wmissing-prototypes -Wmissing-declarations \
-Wstrict-prototypes -Wwrite-strings -Wbad-function-cast \
-Wformat-security -Wno-format-nonliteral -Wmissing-format-attribute \
Expand Down
4 changes: 2 additions & 2 deletions src/detect-engine-mpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1609,8 +1609,8 @@ static void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms)
uint8_t flags = 0;
if ((cd->flags & DETECT_CONTENT_ENDS_WITH) && mpm_supports_endswith)
flags = MPM_PATTERN_FLAG_ENDSWITH;
PopulateMpmHelperAddPattern(
ms->mpm_ctx, cd, s, flags, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP));
PopulateMpmHelperAddPattern(ms->mpm_ctx, cd, s, flags,
(cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) != 0);
}
}
}
Expand Down
24 changes: 6 additions & 18 deletions src/detect-lua.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
#include "util-var-name.h"

#include "util-lua.h"
#include "util-lua-builtins.h"
#include "util-lua-sandbox.h"

static int DetectLuaMatch (DetectEngineThreadCtx *,
Expand Down Expand Up @@ -116,7 +117,6 @@ void DetectLuaRegister(void)
#define FLAG_DATATYPE_DNS_RRNAME BIT_U32(15)
#define FLAG_DATATYPE_DNS_REQUEST BIT_U32(16)
#define FLAG_DATATYPE_DNS_RESPONSE BIT_U32(17)
#define FLAG_DATATYPE_TLS BIT_U32(18)
#define FLAG_DATATYPE_SSH BIT_U32(19)
#define FLAG_DATATYPE_SMTP BIT_U32(20)
#define FLAG_DATATYPE_DNP3 BIT_U32(21)
Expand Down Expand Up @@ -354,16 +354,6 @@ static int DetectLuaMatch (DetectEngineThreadCtx *det_ctx,
lua_getglobal(tlua->luastate, "match");
lua_newtable(tlua->luastate); /* stack at -1 */

if ((tlua->flags & FLAG_DATATYPE_PAYLOAD) && p->payload_len) {
lua_pushliteral(tlua->luastate, "payload"); /* stack at -2 */
LuaPushStringBuffer (tlua->luastate, (const uint8_t *)p->payload, (size_t)p->payload_len); /* stack at -3 */
lua_settable(tlua->luastate, -3);
}
if ((tlua->flags & FLAG_DATATYPE_PACKET) && GET_PKT_LEN(p)) {
lua_pushliteral(tlua->luastate, "packet"); /* stack at -2 */
LuaPushStringBuffer (tlua->luastate, (const uint8_t *)GET_PKT_DATA(p), (size_t)GET_PKT_LEN(p)); /* stack at -3 */
lua_settable(tlua->luastate, -3);
}
if (tlua->alproto == ALPROTO_HTTP1) {
HtpState *htp_state = p->flow->alstate;
if (htp_state != NULL && htp_state->connp != NULL) {
Expand Down Expand Up @@ -485,6 +475,7 @@ static void *DetectLuaThreadInit(void *data)

if (lua->allow_restricted_functions) {
luaL_openlibs(t->luastate);
SCLuaRequirefBuiltIns(t->luastate);
} else {
SCLuaSbLoadLibs(t->luastate);
}
Expand Down Expand Up @@ -600,6 +591,7 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld, const
return -1;
if (ld->allow_restricted_functions) {
luaL_openlibs(luastate);
SCLuaRequirefBuiltIns(luastate);
} else {
SCLuaSbLoadLibs(luastate);
}
Expand Down Expand Up @@ -853,8 +845,6 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld, const

ld->alproto = ALPROTO_TLS;

ld->flags |= FLAG_DATATYPE_TLS;

} else if (strncmp(k, "ssh", 3) == 0 && strcmp(v, "true") == 0) {

ld->alproto = ALPROTO_SSH;
Expand Down Expand Up @@ -901,20 +891,18 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld, const
*/
static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
{
DetectLuaData *lua = NULL;

/* First check if Lua rules are enabled, by default Lua in rules
* is disabled. */
int enabled = 0;
(void)ConfGetBool("security.lua.allow-rules", &enabled);
if (!enabled) {
SCLogError("Lua rules disabled by security configuration: security.lua.allow-rules");
goto error;
return -1;
}

lua = DetectLuaParse(de_ctx, str);
DetectLuaData *lua = DetectLuaParse(de_ctx, str);
if (lua == NULL)
goto error;
return -1;

/* Load lua sandbox configurations */
intmax_t lua_alloc_limit = DEFAULT_LUA_ALLOC_LIMIT;
Expand Down
Loading
Loading