]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
lua: convert ssh function into suricata.ssh lib
authorPhilippe Antoine <pantoine@oisf.net>
Thu, 3 Apr 2025 14:25:19 +0000 (16:25 +0200)
committerVictor Julien <victor@inliniac.net>
Fri, 25 Apr 2025 07:51:48 +0000 (09:51 +0200)
Ticket: 7607

doc/userguide/lua/libs/index.rst
doc/userguide/lua/libs/ssh.rst [new file with mode: 0644]
doc/userguide/lua/lua-functions.rst
src/detect-lua-extensions.c
src/output-lua.c
src/util-lua-builtins.c
src/util-lua-ssh.c
src/util-lua-ssh.h

index a0a87766eace55cff0f36d75d4b645bd2cec9b62..c043da27ad441ab70f810da711884070f5f2bede 100644 (file)
@@ -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 (file)
index 0000000..0416186
--- /dev/null
@@ -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)
index 726864a02884b293885e7b36eb8f1bc36f9989b2..9f02125af848eda46c5856a86d643be4a651f2ef 100644 (file)
@@ -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
 ~~~~~~~~
 
index 67a0d598e15bf54238f82486a7df096c8aafd65f..ba51db8c7e2c8dd1cbe77cc5412d945eda7c7ca0 100644 (file)
@@ -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;
index 10a8c06604e3ac7815c164f022e2c602531c646c..f35adcf52ea3e7babc273a6b6e4c8eb76811d678 100644 (file)
@@ -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);
 
index 7ad5f0e2cc5cca9e0bcbb29a45616dd91cc09e61..2bf22ba3c1a8ae8908464d18e9243fab7dfd1c3a 100644 (file)
@@ -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 },
 };
 
index a2d6d2edaf2a02433b883457503f011527f43814..3332cc8ae5adaec41dc8608d6d3b5e029f446897 100644 (file)
  */
 
 #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;
 }
index c36ef105acb099534b44342865803054c5e9e91d..0e1fbb47907e8a2e5cb6e5551c6a78f0e5b2d9db 100644 (file)
@@ -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 */