]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
lua: convert http fns into suricata.http lib
authorShivani Bhardwaj <shivani@oisf.net>
Wed, 26 Mar 2025 06:20:25 +0000 (11:50 +0530)
committerVictor Julien <victor@inliniac.net>
Tue, 1 Apr 2025 08:17:07 +0000 (10:17 +0200)
Expose the existing lua fns through the library as suricata.http module.
All existing fns are accessible like before with a transaction.

Task 7604

src/detect-lua-extensions.c
src/output-lua.c
src/util-lua-builtins.c
src/util-lua-http.c
src/util-lua-http.h

index eb0de09c52caa52e00b497d8dfbceb7e311cf2dc..6b6ee373113597eb948eacd3069f7dc8beb10b12 100644 (file)
@@ -550,7 +550,6 @@ int LuaRegisterExtensions(lua_State *lua_state)
     lua_setglobal(lua_state, "SCByteVarGet");
 
     LuaRegisterFunctions(lua_state);
-    LuaRegisterHttpFunctions(lua_state);
     LuaRegisterJa3Functions(lua_state);
     LuaRegisterTlsFunctions(lua_state);
     LuaRegisterSshFunctions(lua_state);
index 55c54e9ef300eaf3015b0e8ec884c2cd034de9ad..ad2a8fffc182fff6a578cee0200b4580095d9a6b 100644 (file)
@@ -591,9 +591,6 @@ static lua_State *LuaScriptSetup(const char *filename, LogLuaMasterCtx *ctx)
 
     /* register functions common to all */
     LuaRegisterFunctions(luastate);
-    /* unconditionally register http function. They will only work
-     * if the tx is registered in the state at runtime though. */
-    LuaRegisterHttpFunctions(luastate);
     LuaRegisterJa3Functions(luastate);
     LuaRegisterTlsFunctions(luastate);
     LuaRegisterSshFunctions(luastate);
index 8b511cbc77862de58f757ef15781c18846397d9d..84eeb0178867611778f4c7a0b0f16403c543b214 100644 (file)
@@ -20,6 +20,7 @@
 #include "util-lua-base64lib.h"
 #include "util-lua-dataset.h"
 #include "util-lua-dnp3.h"
+#include "util-lua-http.h"
 #include "util-lua-dns.h"
 #include "util-lua-flowlib.h"
 #include "util-lua-hashlib.h"
@@ -34,6 +35,7 @@ static const luaL_Reg builtins[] = {
     { "suricata.dns", SCLuaLoadDnsLib },
     { "suricata.flow", LuaLoadFlowLib },
     { "suricata.hashlib", SCLuaLoadHashlib },
+    { "suricata.http", SCLuaLoadHttpLib },
     { "suricata.packet", LuaLoadPacketLib },
     { NULL, NULL },
 };
index 6c3a512df9b8c4aa4d7d71bfcdf2c3983fd39e9f..9a269d2fb77ad01dc6ee172f6eb5bf3b2fd93777 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2014 Open Information Security Foundation
+/* Copyright (C) 2014-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
  */
 
 #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-htp.h"
-#include "app-layer.h"
-#include "app-layer-parser.h"
-#include "util-privs.h"
-#include "util-buffer.h"
-#include "util-proto-name.h"
-#include "util-logopenfile.h"
-#include "util-time.h"
-
-#include "lua.h"
-#include "lualib.h"
-#include "lauxlib.h"
-
 #include "util-lua.h"
 #include "util-lua-common.h"
 #include "util-lua-http.h"
 
-static int HttpGetRequestHost(lua_State *luastate)
+static const char htp_tx[] = "suricata:http:tx";
+
+struct LuaTx {
+    htp_tx_t *tx;
+};
+
+static int LuaHttpGetTx(lua_State *luastate)
 {
-    if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
+    if (!LuaStateNeedProto(luastate, ALPROTO_HTTP1)) {
         return LuaCallbackError(luastate, "error: protocol not http");
+    }
 
     htp_tx_t *tx = LuaStateGetTX(luastate);
-    if (tx == NULL)
-        return LuaCallbackError(luastate, "internal error: no tx");
+    if (tx == NULL) {
+        return LuaCallbackError(luastate, "error: no tx available");
+    }
+    struct LuaTx *ltx = (struct LuaTx *)lua_newuserdata(luastate, sizeof(*ltx));
+    if (ltx == NULL) {
+        return LuaCallbackError(luastate, "error: failed to allocate user data");
+    }
 
-    if (htp_tx_request_hostname(tx) == NULL)
-        return LuaCallbackError(luastate, "no request hostname");
+    ltx->tx = tx;
 
-    return LuaPushStringBuffer(
-            luastate, bstr_ptr(htp_tx_request_hostname(tx)), bstr_len(htp_tx_request_hostname(tx)));
+    luaL_getmetatable(luastate, htp_tx);
+    lua_setmetatable(luastate, -2);
+
+    return 1;
 }
 
-static int HttpGetRequestUriRaw(lua_State *luastate)
+static int LuaHttpGetRequestHost(lua_State *luastate)
 {
-    if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
-        return LuaCallbackError(luastate, "error: protocol not http");
+    struct LuaTx *tx = luaL_testudata(luastate, 1, htp_tx);
+    if (tx == NULL) {
+        lua_pushnil(luastate);
+        return 1;
+    }
 
-    htp_tx_t *tx = LuaStateGetTX(luastate);
-    if (tx == NULL)
-        return LuaCallbackError(luastate, "internal error: no tx");
+    return LuaPushStringBuffer(luastate, bstr_ptr(htp_tx_request_hostname(tx->tx)),
+            bstr_len(htp_tx_request_hostname(tx->tx)));
+}
 
-    if (htp_tx_request_uri(tx) == NULL)
-        return LuaCallbackError(luastate, "no request uri");
+static int LuaHttpGetRequestUriRaw(lua_State *luastate)
+{
+    struct LuaTx *tx = luaL_testudata(luastate, 1, htp_tx);
+    if (tx == NULL) {
+        lua_pushnil(luastate);
+        return 1;
+    }
 
     return LuaPushStringBuffer(
-            luastate, bstr_ptr(htp_tx_request_uri(tx)), bstr_len(htp_tx_request_uri(tx)));
+            luastate, bstr_ptr(htp_tx_request_uri(tx->tx)), bstr_len(htp_tx_request_uri(tx->tx)));
 }
 
-static int HttpGetRequestUriNormalized(lua_State *luastate)
+static int LuaHttpGetRequestUriNormalized(lua_State *luastate)
 {
-    if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
-        return LuaCallbackError(luastate, "error: protocol not http");
-
-    htp_tx_t *tx = LuaStateGetTX(luastate);
-    if (tx == NULL)
-        return LuaCallbackError(luastate, "internal error: no tx");
-
-    HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
+    struct LuaTx *tx = luaL_testudata(luastate, 1, htp_tx);
+    if (tx == NULL) {
+        lua_pushnil(luastate);
+        return 1;
+    }
+    HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx->tx);
     if (htud == NULL)
         return LuaCallbackError(luastate, "no htud in tx");
 
@@ -109,84 +103,76 @@ static int HttpGetRequestUriNormalized(lua_State *luastate)
             bstr_len(htud->request_uri_normalized));
 }
 
-static int HttpGetRequestLine(lua_State *luastate)
+static int LuaHttpGetRequestLine(lua_State *luastate)
 {
-    if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
-        return LuaCallbackError(luastate, "error: protocol not http");
-
-    htp_tx_t *tx = LuaStateGetTX(luastate);
-    if (tx == NULL)
-        return LuaCallbackError(luastate, "internal error: no tx");
-
-    if (htp_tx_request_line(tx) == NULL)
-        return LuaCallbackError(luastate, "no request_line");
+    struct LuaTx *tx = luaL_testudata(luastate, 1, htp_tx);
+    if (tx == NULL) {
+        lua_pushnil(luastate);
+        return 1;
+    }
 
     return LuaPushStringBuffer(
-            luastate, bstr_ptr(htp_tx_request_line(tx)), bstr_len(htp_tx_request_line(tx)));
+            luastate, bstr_ptr(htp_tx_request_line(tx->tx)), bstr_len(htp_tx_request_line(tx->tx)));
 }
 
-static int HttpGetResponseLine(lua_State *luastate)
+static int LuaHttpGetResponseLine(lua_State *luastate)
 {
-    if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
-        return LuaCallbackError(luastate, "error: protocol not http");
-
-    htp_tx_t *tx = LuaStateGetTX(luastate);
-    if (tx == NULL)
-        return LuaCallbackError(luastate, "internal error: no tx");
-
-    if (htp_tx_response_line(tx) == NULL)
-        return LuaCallbackError(luastate, "no response_line");
+    struct LuaTx *tx = luaL_testudata(luastate, 1, htp_tx);
+    if (tx == NULL) {
+        lua_pushnil(luastate);
+        return 1;
+    }
 
-    return LuaPushStringBuffer(
-            luastate, bstr_ptr(htp_tx_response_line(tx)), bstr_len(htp_tx_response_line(tx)));
+    return LuaPushStringBuffer(luastate, bstr_ptr(htp_tx_response_line(tx->tx)),
+            bstr_len(htp_tx_response_line(tx->tx)));
 }
 
-static int HttpGetHeader(lua_State *luastate, int dir)
+static int LuaHttpGetHeader(lua_State *luastate, int dir)
 {
-    if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
-        return LuaCallbackError(luastate, "error: protocol not http");
-
-    htp_tx_t *tx = LuaStateGetTX(luastate);
-    if (tx == NULL)
-        return LuaCallbackError(luastate, "internal error: no tx");
+    struct LuaTx *tx = luaL_testudata(luastate, 1, htp_tx);
+    if (tx == NULL) {
+        lua_pushnil(luastate);
+        return 1;
+    }
 
-    const char *name = LuaGetStringArgument(luastate, 1);
-    if (name == NULL)
-        return LuaCallbackError(luastate, "1st argument missing, empty or wrong type");
+    /* since arg was added at last, it must be on top of the stack */
+    const char *name = LuaGetStringArgument(luastate, lua_gettop(luastate));
+    if (name == NULL) {
+        return LuaCallbackError(luastate, "argument missing, empty or wrong type");
+    }
 
     const htp_header_t *h = NULL;
     if (dir == 0) {
-        h = htp_tx_request_header(tx, name);
+        h = htp_tx_request_header(tx->tx, name);
     } else {
-        h = htp_tx_response_header(tx, name);
+        h = htp_tx_response_header(tx->tx, name);
     }
 
-    if (h == NULL || htp_header_value_len(h) == 0)
+    if (h == NULL || htp_header_value_len(h) == 0) {
         return LuaCallbackError(luastate, "header not found");
+    }
 
     return LuaPushStringBuffer(luastate, htp_header_value_ptr(h), htp_header_value_len(h));
 }
 
-static int HttpGetRequestHeader(lua_State *luastate)
+static int LuaHttpGetRequestHeader(lua_State *luastate)
 {
-    return HttpGetHeader(luastate, 0 /* request */);
+    return LuaHttpGetHeader(luastate, 0 /* request */);
 }
 
-static int HttpGetResponseHeader(lua_State *luastate)
+static int LuaHttpGetResponseHeader(lua_State *luastate)
 {
-    return HttpGetHeader(luastate, 1 /* response */);
+    return LuaHttpGetHeader(luastate, 1 /* response */);
 }
 
-static int HttpGetRawHeaders(lua_State *luastate, int dir)
+static int LuaHttpGetRawHeaders(lua_State *luastate, int dir)
 {
-    if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
-        return LuaCallbackError(luastate, "error: protocol not http");
-
-    htp_tx_t *tx = LuaStateGetTX(luastate);
-    if (tx == NULL)
-        return LuaCallbackError(luastate, "internal error: no tx");
-
-    HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
+    struct LuaTx *tx = luaL_testudata(luastate, 1, htp_tx);
+    if (tx == NULL) {
+        lua_pushnil(luastate);
+        return 1;
+    }
+    HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx->tx);
     if (htud == NULL)
         return LuaCallbackError(luastate, "no htud in tx");
 
@@ -203,31 +189,31 @@ static int HttpGetRawHeaders(lua_State *luastate, int dir)
     return LuaPushStringBuffer(luastate, raw, raw_len);
 }
 
-static int HttpGetRawRequestHeaders(lua_State *luastate)
+static int LuaHttpGetRawRequestHeaders(lua_State *luastate)
 {
-    return HttpGetRawHeaders(luastate, 0);
+    return LuaHttpGetRawHeaders(luastate, 0);
 }
 
-static int HttpGetRawResponseHeaders(lua_State *luastate)
+static int LuaHttpGetRawResponseHeaders(lua_State *luastate)
 {
-    return HttpGetRawHeaders(luastate, 1);
+    return LuaHttpGetRawHeaders(luastate, 1);
 }
 
-
-static int HttpGetHeaders(lua_State *luastate, int dir)
+static int LuaHttpGetHeaders(lua_State *luastate, int dir)
 {
-    if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
-        return LuaCallbackError(luastate, "error: protocol not http");
-
-    htp_tx_t *tx = LuaStateGetTX(luastate);
-    if (tx == NULL)
-        return LuaCallbackError(luastate, "internal error: no tx");
+    struct LuaTx *tx = luaL_testudata(luastate, 1, htp_tx);
+    if (tx == NULL) {
+        lua_pushnil(luastate);
+        return 1;
+    }
 
-    const htp_headers_t *table = htp_tx_request_headers(tx);
+    const htp_headers_t *table = htp_tx_request_headers(tx->tx);
     if (dir == 1)
-        table = htp_tx_response_headers(tx);
-    if (table == NULL)
-        return LuaCallbackError(luastate, "no headers");
+        table = htp_tx_response_headers(tx->tx);
+    if (table == NULL) {
+        lua_pushnil(luastate);
+        return 1;
+    }
 
     lua_newtable(luastate);
     const htp_header_t *h = NULL;
@@ -243,39 +229,38 @@ static int HttpGetHeaders(lua_State *luastate, int dir)
 }
 
 /** \brief return request headers as lua table */
-static int HttpGetRequestHeaders(lua_State *luastate)
+static int LuaHttpGetRequestHeaders(lua_State *luastate)
 {
-    return HttpGetHeaders(luastate, 0);
+    return LuaHttpGetHeaders(luastate, 0);
 }
 
 /** \brief return response headers as lua table */
-static int HttpGetResponseHeaders(lua_State *luastate)
+static int LuaHttpGetResponseHeaders(lua_State *luastate)
 {
-    return HttpGetHeaders(luastate, 1);
+    return LuaHttpGetHeaders(luastate, 1);
 }
 
-static int HttpGetBody(lua_State *luastate, int dir)
+static int LuaHttpGetBody(lua_State *luastate, int dir)
 {
-    HtpBody *body = NULL;
-
-    if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
-        return LuaCallbackError(luastate, "error: protocol not http");
-
-    htp_tx_t *tx = LuaStateGetTX(luastate);
-    if (tx == NULL)
-        return LuaCallbackError(luastate, "internal error: no tx");
+    struct LuaTx *tx = luaL_testudata(luastate, 1, htp_tx);
+    if (tx == NULL) {
+        lua_pushnil(luastate);
+        return 1;
+    }
 
-    HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
+    HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx->tx);
     if (htud == NULL)
         return LuaCallbackError(luastate, "no htud in tx");
 
+    HtpBody *body = NULL;
     if (dir == 0)
         body = &htud->request_body;
     else
         body = &htud->response_body;
 
-    if (body->first == NULL)
-        return LuaCallbackError(luastate, "no body");
+    if (body->first == NULL) {
+        return LuaCallbackError(luastate, "no body found");
+    }
 
     int index = 1;
     HtpBodyChunk *chunk = body->first;
@@ -303,46 +288,48 @@ static int HttpGetBody(lua_State *luastate, int dir)
     }
 }
 
-static int HttpGetRequestBody(lua_State *luastate)
+static int LuaHttpGetRequestBody(lua_State *luastate)
 {
-    return HttpGetBody(luastate, 0);
+    return LuaHttpGetBody(luastate, 0);
 }
 
-static int HttpGetResponseBody(lua_State *luastate)
+static int LuaHttpGetResponseBody(lua_State *luastate)
 {
-    return HttpGetBody(luastate, 1);
+    return LuaHttpGetBody(luastate, 1);
 }
 
-/** \brief register http lua extensions in a luastate */
-int LuaRegisterHttpFunctions(lua_State *luastate)
+static const struct luaL_Reg txlib[] = {
+    // clang-format off
+    {"request_header", LuaHttpGetRequestHeader},
+    {"response_header", LuaHttpGetResponseHeader},
+    {"request_line", LuaHttpGetRequestLine},
+    {"response_line", LuaHttpGetResponseLine},
+    {"request_headers_raw", LuaHttpGetRawRequestHeaders},
+    {"response_headers_raw", LuaHttpGetRawResponseHeaders},
+    {"request_uri_raw", LuaHttpGetRequestUriRaw},
+    {"request_uri_normalized", LuaHttpGetRequestUriNormalized},
+    {"request_headers", LuaHttpGetRequestHeaders},
+    {"response_headers", LuaHttpGetResponseHeaders},
+    {"request_host", LuaHttpGetRequestHost},
+    {"request_body", LuaHttpGetRequestBody},
+    {"response_body", LuaHttpGetResponseBody},
+    {NULL, NULL,},
+    // clang-format on
+};
+
+static const struct luaL_Reg htplib[] = {
+    // clang-format off
+    {"get_tx", LuaHttpGetTx },
+    {NULL, NULL,},
+    // clang-format on
+};
+
+int SCLuaLoadHttpLib(lua_State *luastate)
 {
-    /* registration of the callbacks */
-    lua_pushcfunction(luastate, HttpGetRequestHeader);
-    lua_setglobal(luastate, "HttpGetRequestHeader");
-    lua_pushcfunction(luastate, HttpGetResponseHeader);
-    lua_setglobal(luastate, "HttpGetResponseHeader");
-    lua_pushcfunction(luastate, HttpGetRequestLine);
-    lua_setglobal(luastate, "HttpGetRequestLine");
-    lua_pushcfunction(luastate, HttpGetResponseLine);
-    lua_setglobal(luastate, "HttpGetResponseLine");
-    lua_pushcfunction(luastate, HttpGetRawRequestHeaders);
-    lua_setglobal(luastate, "HttpGetRawRequestHeaders");
-    lua_pushcfunction(luastate, HttpGetRawResponseHeaders);
-    lua_setglobal(luastate, "HttpGetRawResponseHeaders");
-    lua_pushcfunction(luastate, HttpGetRequestUriRaw);
-    lua_setglobal(luastate, "HttpGetRequestUriRaw");
-    lua_pushcfunction(luastate, HttpGetRequestUriNormalized);
-    lua_setglobal(luastate, "HttpGetRequestUriNormalized");
-    lua_pushcfunction(luastate, HttpGetRequestHeaders);
-    lua_setglobal(luastate, "HttpGetRequestHeaders");
-    lua_pushcfunction(luastate, HttpGetResponseHeaders);
-    lua_setglobal(luastate, "HttpGetResponseHeaders");
-    lua_pushcfunction(luastate, HttpGetRequestHost);
-    lua_setglobal(luastate, "HttpGetRequestHost");
-
-    lua_pushcfunction(luastate, HttpGetRequestBody);
-    lua_setglobal(luastate, "HttpGetRequestBody");
-    lua_pushcfunction(luastate, HttpGetResponseBody);
-    lua_setglobal(luastate, "HttpGetResponseBody");
-    return 0;
+    luaL_newmetatable(luastate, htp_tx);
+    lua_pushvalue(luastate, -1);
+    lua_setfield(luastate, -2, "__index");
+    luaL_setfuncs(luastate, txlib, 0);
+    luaL_newlib(luastate, htplib);
+    return 1;
 }
index d6b0d43b7541170ebe96550e7a5402010100904c..e4eac25b8938d252678924d1800c3fe39551ac97 100644 (file)
@@ -24,6 +24,8 @@
 #ifndef SURICATA_UTIL_LUA_HTTP_H
 #define SURICATA_UTIL_LUA_HTTP_H
 
-int LuaRegisterHttpFunctions(lua_State *luastate);
+#include "lua.h"
+
+int SCLuaLoadHttpLib(lua_State *);
 
 #endif /* SURICATA_UTIL_LUA_HTTP_H */