From: Philippe Antoine Date: Thu, 3 Apr 2025 14:25:19 +0000 (+0200) Subject: lua: convert ssh function into suricata.ssh lib X-Git-Tag: suricata-8.0.0-rc1~414 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=76d7ab54186f48f2b0c53344a94856d7b41f3a1a;p=thirdparty%2Fsuricata.git lua: convert ssh function into suricata.ssh lib Ticket: 7607 --- diff --git a/doc/userguide/lua/libs/index.rst b/doc/userguide/lua/libs/index.rst index a0a87766ea..c043da27ad 100644 --- a/doc/userguide/lua/libs/index.rst +++ b/doc/userguide/lua/libs/index.rst @@ -15,3 +15,4 @@ environment without access to additional modules. http packetlib rule + ssh diff --git a/doc/userguide/lua/libs/ssh.rst b/doc/userguide/lua/libs/ssh.rst new file mode 100644 index 0000000000..0416186cbc --- /dev/null +++ b/doc/userguide/lua/libs/ssh.rst @@ -0,0 +1,89 @@ +SSH +--- + +SSH transaction details are exposes to Lua scripts with the +``suricata.ssh`` library, For example:: + + local ssh = require("suricata.ssh") + +Setup +^^^^^ + +If your purpose is to create a logging script, initialize the buffer as: + +:: + + function init (args) + local needs = {} + return needs + end + +If you are going to use the script for rule matching, choose one of +the available SSH buffers listed in :ref:`lua-detection` and follow +the pattern: + +:: + + function init (args) + local needs = {} + return needs + end + +Transaction +~~~~~~~~~~~ + +SSH is transaction based, and the current transaction must be obtained before use:: + + local tx, err = ssh.get_tx() + if tx == err then + print(err) + end + +All other functions are methods on the transaction table. + +Transaction Methods +~~~~~~~~~~~~~~~~~~~ + +``server_proto()`` +^^^^^^^^^^^^^^^^^^ + +Get the ``server_proto`` value as a string. + +Example:: + + local tx = ssh.get_tx() + local proto = tx:server_proto(); + print (proto) + +``client_proto()`` +^^^^^^^^^^^^^^^^^^ + +Get the ``client_proto`` value as a string. + +Example:: + + local tx = ssh.get_tx() + local proto = tx:client_proto(); + print (proto) + +``server_software()`` +^^^^^^^^^^^^^^^^^^^^^ + +Get the ``server_software`` value as a string. + +Example:: + + local tx = ssh.get_tx() + local software = tx:server_software(); + print (software) + +``client_software()`` +^^^^^^^^^^^^^^^^^^^^^ + +Get the ``client_software`` value as a string. + +Example:: + + local tx = ssh.get_tx() + local software = tx:client_software(); + print (software) diff --git a/doc/userguide/lua/lua-functions.rst b/doc/userguide/lua/lua-functions.rst index 726864a028..9f02125af8 100644 --- a/doc/userguide/lua/lua-functions.rst +++ b/doc/userguide/lua/lua-functions.rst @@ -481,71 +481,6 @@ Initialize with: return needs end -SshGetServerProtoVersion -~~~~~~~~~~~~~~~~~~~~~~~~ - -Get SSH protocol version used by the server through SshGetServerProtoVersion. - -Example: - -:: - - function log (args) - version = SshGetServerProtoVersion() - if version == nil then - return 0 - end - end - -SshGetServerSoftwareVersion -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Get SSH software used by the server through SshGetServerSoftwareVersion. - -Example: - -:: - - function log (args) - software = SshGetServerSoftwareVersion() - if software == nil then - return 0 - end - end - -SshGetClientProtoVersion -~~~~~~~~~~~~~~~~~~~~~~~~ - -Get SSH protocol version used by the client through SshGetClientProtoVersion. - -Example: - -:: - - function log (args) - version = SshGetClientProtoVersion() - if version == nil then - return 0 - end - end - -SshGetClientSoftwareVersion -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Get SSH software used by the client through SshGetClientSoftwareVersion. - -Example: - -:: - - function log (args) - software = SshGetClientSoftwareVersion() - if software == nil then - return 0 - end - end - - HasshGet ~~~~~~~~ diff --git a/src/detect-lua-extensions.c b/src/detect-lua-extensions.c index 67a0d598e1..ba51db8c7e 100644 --- a/src/detect-lua-extensions.c +++ b/src/detect-lua-extensions.c @@ -42,7 +42,6 @@ #include "util-lua-http.h" #include "util-lua-ja3.h" #include "util-lua-tls.h" -#include "util-lua-ssh.h" #include "util-lua-hassh.h" #include "util-lua-smtp.h" #include "util-lua-dnp3.h" @@ -551,7 +550,6 @@ int LuaRegisterExtensions(lua_State *lua_state) LuaRegisterFunctions(lua_state); LuaRegisterJa3Functions(lua_state); LuaRegisterTlsFunctions(lua_state); - LuaRegisterSshFunctions(lua_state); LuaRegisterHasshFunctions(lua_state); LuaRegisterSmtpFunctions(lua_state); return 0; diff --git a/src/output-lua.c b/src/output-lua.c index 10a8c06604..f35adcf52e 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -38,7 +38,6 @@ #include "util-lua-http.h" #include "util-lua-ja3.h" #include "util-lua-tls.h" -#include "util-lua-ssh.h" #include "util-lua-hassh.h" #include "util-lua-smtp.h" @@ -592,7 +591,6 @@ static lua_State *LuaScriptSetup(const char *filename, LogLuaMasterCtx *ctx) LuaRegisterFunctions(luastate); LuaRegisterJa3Functions(luastate); LuaRegisterTlsFunctions(luastate); - LuaRegisterSshFunctions(luastate); LuaRegisterHasshFunctions(luastate); LuaRegisterSmtpFunctions(luastate); diff --git a/src/util-lua-builtins.c b/src/util-lua-builtins.c index 7ad5f0e2cc..2bf22ba3c1 100644 --- a/src/util-lua-builtins.c +++ b/src/util-lua-builtins.c @@ -22,6 +22,7 @@ #include "util-lua-dnp3.h" #include "util-lua-http.h" #include "util-lua-dns.h" +#include "util-lua-ssh.h" #include "util-lua-flowlib.h" #include "util-lua-hashlib.h" #include "util-lua-packetlib.h" @@ -39,6 +40,7 @@ static const luaL_Reg builtins[] = { { "suricata.http", SCLuaLoadHttpLib }, { "suricata.packet", LuaLoadPacketLib }, { "suricata.rule", SCLuaLoadRuleLib }, + { "suricata.ssh", SCLuaLoadSshLib }, { NULL, NULL }, }; diff --git a/src/util-lua-ssh.c b/src/util-lua-ssh.c index a2d6d2edaf..3332cc8ae5 100644 --- a/src/util-lua-ssh.c +++ b/src/util-lua-ssh.c @@ -24,192 +24,115 @@ */ #include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-print.h" -#include "util-unittest.h" - -#include "util-debug.h" - -#include "output.h" -#include "app-layer.h" -#include "app-layer-parser.h" -#include "app-layer-ssh.h" -#include "util-privs.h" -#include "util-buffer.h" -#include "util-proto-name.h" -#include "util-logopenfile.h" -#include "util-time.h" -#include "rust.h" - -#include "lua.h" -#include "lualib.h" -#include "lauxlib.h" - +#include "util-lua-ssh.h" #include "util-lua.h" #include "util-lua-common.h" -#include "util-lua-ssh.h" - -static int GetServerProtoVersion(lua_State *luastate, const Flow *f) -{ - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no app layer state"); - const uint8_t *protocol = NULL; - uint32_t b_len = 0; +#include "rust.h" - void *tx = SCSshStateGetTx(state, 0); - if (SCSshTxGetProtocol(tx, &protocol, &b_len, STREAM_TOCLIENT) != 1) - return LuaCallbackError(luastate, "error: no server proto version"); - if (protocol == NULL || b_len == 0) { - return LuaCallbackError(luastate, "error: no server proto version"); - } +// #define SSH_MT "suricata:ssh:tx" +static const char ssh_tx[] = "suricata:ssh:tx"; - return LuaPushStringBuffer(luastate, protocol, b_len); -} +struct LuaTx { + void *tx; // SSHTransaction +}; -static int SshGetServerProtoVersion(lua_State *luastate) +static int LuaSshGetTx(lua_State *L) { - int r; - - if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) - return LuaCallbackError(luastate, "error: protocol not ssh"); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); + if (!(LuaStateNeedProto(L, ALPROTO_SSH))) { + return LuaCallbackError(L, "error: protocol not ssh"); + } + void *tx = LuaStateGetTX(L); + if (tx == NULL) { + return LuaCallbackError(L, "error: no tx available"); + } + struct LuaTx *ltx = (struct LuaTx *)lua_newuserdata(L, sizeof(*ltx)); + if (ltx == NULL) { + return LuaCallbackError(L, "error: fail to allocate user data"); + } + ltx->tx = tx; - r = GetServerProtoVersion(luastate, f); + luaL_getmetatable(L, ssh_tx); + lua_setmetatable(L, -2); - return r; + return 1; } -static int GetServerSoftwareVersion(lua_State *luastate, const Flow *f) +static int LuaSshTxGetProto(lua_State *L, uint8_t flags) { - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no app layer state"); - - const uint8_t *software = NULL; + const uint8_t *buf = NULL; uint32_t b_len = 0; - - void *tx = SCSshStateGetTx(state, 0); - if (SCSshTxGetSoftware(tx, &software, &b_len, STREAM_TOCLIENT) != 1) - return LuaCallbackError(luastate, "error: no server software version"); - if (software == NULL || b_len == 0) { - return LuaCallbackError(luastate, "error: no server software version"); + struct LuaTx *ltx = luaL_testudata(L, 1, ssh_tx); + if (ltx == NULL) { + lua_pushnil(L); + return 1; } - - return LuaPushStringBuffer(luastate, software, b_len); -} - -static int SshGetServerSoftwareVersion(lua_State *luastate) -{ - int r; - - if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) - return LuaCallbackError(luastate, "error: protocol not ssh"); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - r = GetServerSoftwareVersion(luastate, f); - - return r; + if (SCSshTxGetProtocol(ltx->tx, &buf, &b_len, flags) != 1) { + lua_pushnil(L); + return 1; + } + return LuaPushStringBuffer(L, buf, b_len); } -static int GetClientProtoVersion(lua_State *luastate, const Flow *f) +static int LuaSshTxGetServerProto(lua_State *L) { - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no app layer state"); - - const uint8_t *protocol = NULL; - uint32_t b_len = 0; - - void *tx = SCSshStateGetTx(state, 0); - if (SCSshTxGetProtocol(tx, &protocol, &b_len, STREAM_TOSERVER) != 1) - return LuaCallbackError(luastate, "error: no client proto version"); - if (protocol == NULL || b_len == 0) { - return LuaCallbackError(luastate, "error: no client proto version"); - } - - return LuaPushStringBuffer(luastate, protocol, b_len); + return LuaSshTxGetProto(L, STREAM_TOCLIENT); } -static int SshGetClientProtoVersion(lua_State *luastate) +static int LuaSshTxGetClientProto(lua_State *L) { - int r; - - if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) - return LuaCallbackError(luastate, "error: protocol not ssh"); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - r = GetClientProtoVersion(luastate, f); - - return r; + return LuaSshTxGetProto(L, STREAM_TOSERVER); } -static int GetClientSoftwareVersion(lua_State *luastate, const Flow *f) +static int LuaSshTxGetSoftware(lua_State *L, uint8_t flags) { - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no app layer state"); - - const uint8_t *software = NULL; + const uint8_t *buf = NULL; uint32_t b_len = 0; - - void *tx = SCSshStateGetTx(state, 0); - if (SCSshTxGetSoftware(tx, &software, &b_len, STREAM_TOSERVER) != 1) - return LuaCallbackError(luastate, "error: no client software version"); - if (software == NULL || b_len == 0) { - return LuaCallbackError(luastate, "error: no client software version"); + struct LuaTx *ltx = luaL_testudata(L, 1, ssh_tx); + if (ltx == NULL) { + lua_pushnil(L); + return 1; } - - return LuaPushStringBuffer(luastate, software, b_len); + if (SCSshTxGetSoftware(ltx->tx, &buf, &b_len, flags) != 1) { + lua_pushnil(L); + return 1; + } + return LuaPushStringBuffer(L, buf, b_len); } -static int SshGetClientSoftwareVersion(lua_State *luastate) +static int LuaSshTxGetServerSoftware(lua_State *L) { - int r; - - if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) - return LuaCallbackError(luastate, "error: protocol not ssh"); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - r = GetClientSoftwareVersion(luastate, f); - - return r; + return LuaSshTxGetSoftware(L, STREAM_TOCLIENT); } -/** \brief register ssh lua extensions in a luastate */ -int LuaRegisterSshFunctions(lua_State *luastate) +static int LuaSshTxGetClientSoftware(lua_State *L) { - /* registration of the callbacks */ - lua_pushcfunction(luastate, SshGetServerProtoVersion); - lua_setglobal(luastate, "SshGetServerProtoVersion"); - - lua_pushcfunction(luastate, SshGetServerSoftwareVersion); - lua_setglobal(luastate, "SshGetServerSoftwareVersion"); - - lua_pushcfunction(luastate, SshGetClientProtoVersion); - lua_setglobal(luastate, "SshGetClientProtoVersion"); + return LuaSshTxGetSoftware(L, STREAM_TOSERVER); +} - lua_pushcfunction(luastate, SshGetClientSoftwareVersion); - lua_setglobal(luastate, "SshGetClientSoftwareVersion"); +static const struct luaL_Reg txlib[] = { + // clang-format off + { "server_proto", LuaSshTxGetServerProto }, + { "server_software", LuaSshTxGetServerSoftware }, + { "client_proto", LuaSshTxGetClientProto }, + { "client_software", LuaSshTxGetClientSoftware }, + { NULL, NULL, } + // clang-format on +}; + +static const struct luaL_Reg sshlib[] = { + // clang-format off + { "get_tx", LuaSshGetTx }, + { NULL, NULL,}, + // clang-format on +}; + +int SCLuaLoadSshLib(lua_State *L) +{ + luaL_newmetatable(L, ssh_tx); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + luaL_setfuncs(L, txlib, 0); - return 0; + luaL_newlib(L, sshlib); + return 1; } diff --git a/src/util-lua-ssh.h b/src/util-lua-ssh.h index c36ef105ac..0e1fbb4790 100644 --- a/src/util-lua-ssh.h +++ b/src/util-lua-ssh.h @@ -24,6 +24,8 @@ #ifndef SURICATA_UTIL_LUA_SSH_H #define SURICATA_UTIL_LUA_SSH_H -int LuaRegisterSshFunctions(lua_State *luastate); +#include "lua.h" + +int SCLuaLoadSshLib(lua_State *L); #endif /* SURICATA_UTIL_LUA_SSH_H */