]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
lua: fix http.request_line inspection
authorVictor Julien <victor@inliniac.net>
Thu, 18 Sep 2014 11:37:18 +0000 (13:37 +0200)
committerVictor Julien <victor@inliniac.net>
Fri, 19 Sep 2014 08:50:25 +0000 (10:50 +0200)
As there is no inspection engine for request_line, the sigmatch was
added to the AMATCH list. However, no AppLayerMatch function for
lua scripts was defined.

This patch defines a AppLayerMatch function.

Bug #1273.

src/detect-lua.c

index 75364136ff2ee3d85f4b53e8a506275362591816..04d7394f95f42b6c1ef2927c71777684d86038dc 100644 (file)
@@ -109,6 +109,8 @@ static pthread_mutex_t luajit_states_lock = SCMUTEX_INITIALIZER;
 
 static int DetectLuaMatch (ThreadVars *, DetectEngineThreadCtx *,
         Packet *, Signature *, SigMatch *);
+static int DetectLuaAppMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx,
+        Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m);
 static int DetectLuaSetup (DetectEngineCtx *, Signature *, char *);
 static void DetectLuaRegisterTests(void);
 static void DetectLuaFree(void *);
@@ -123,6 +125,7 @@ void DetectLuaRegister(void)
     sigmatch_table[DETECT_LUA].desc = "match via a luajit script";
     sigmatch_table[DETECT_LUA].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Lua_scripting";
     sigmatch_table[DETECT_LUA].Match = DetectLuaMatch;
+    sigmatch_table[DETECT_LUA].AppLayerMatch = DetectLuaAppMatch;
     sigmatch_table[DETECT_LUA].Setup = DetectLuaSetup;
     sigmatch_table[DETECT_LUA].Free  = DetectLuaFree;
     sigmatch_table[DETECT_LUA].RegisterTests = DetectLuaRegisterTests;
@@ -505,6 +508,118 @@ static int DetectLuaMatch (ThreadVars *tv, DetectEngineThreadCtx *det_ctx,
     SCReturnInt(ret);
 }
 
+/**
+ * \brief match the specified lua script in AMATCH
+ *
+ * \param t thread local vars
+ * \param det_ctx pattern matcher thread local data
+ * \param s signature being inspected
+ * \param m sigmatch that we will cast into DetectLuaData
+ *
+ * \retval 0 no match
+ * \retval 1 match
+ */
+static int DetectLuaAppMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx,
+        Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m)
+{
+    SCEnter();
+    int ret = 0;
+    DetectLuaData *luajit = (DetectLuaData *)m->ctx;
+    if (luajit == NULL)
+        SCReturnInt(0);
+
+    DetectLuaThreadData *tluajit = (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, luajit->thread_ctx_id);
+    if (tluajit == NULL)
+        SCReturnInt(0);
+
+    /* setup extension data for use in lua c functions */
+    LuaExtensionsMatchSetup(tluajit->luastate, luajit, det_ctx,
+            f, /* flow is locked */LUA_FLOW_LOCKED_BY_PARENT, NULL);
+
+    if (tluajit->alproto != ALPROTO_UNKNOWN) {
+        int alproto = f->alproto;
+        if (tluajit->alproto != alproto)
+            SCReturnInt(0);
+    }
+
+    lua_getglobal(tluajit->luastate, "match");
+    lua_newtable(tluajit->luastate); /* stack at -1 */
+
+    if (tluajit->alproto == ALPROTO_HTTP) {
+        HtpState *htp_state = state;
+        if (htp_state != NULL && htp_state->connp != NULL) {
+            htp_tx_t *tx = NULL;
+            tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, det_ctx->tx_id);
+            if (tx != NULL) {
+                if ((tluajit->flags & DATATYPE_HTTP_REQUEST_LINE) && tx->request_line != NULL &&
+                    bstr_len(tx->request_line) > 0) {
+                    lua_pushliteral(tluajit->luastate, "http.request_line"); /* stack at -2 */
+                    LuaPushStringBuffer(tluajit->luastate,
+                                     (const uint8_t *)bstr_ptr(tx->request_line),
+                                     bstr_len(tx->request_line));
+                    lua_settable(tluajit->luastate, -3);
+                }
+            }
+        }
+    }
+
+    int retval = lua_pcall(tluajit->luastate, 1, 1, 0);
+    if (retval != 0) {
+        SCLogInfo("failed to run script: %s", lua_tostring(tluajit->luastate, -1));
+    }
+
+    /* process returns from script */
+    if (lua_gettop(tluajit->luastate) > 0) {
+
+        /* script returns a number (return 1 or return 0) */
+        if (lua_type(tluajit->luastate, 1) == LUA_TNUMBER) {
+            double script_ret = lua_tonumber(tluajit->luastate, 1);
+            SCLogDebug("script_ret %f", script_ret);
+            lua_pop(tluajit->luastate, 1);
+
+            if (script_ret == 1.0)
+                ret = 1;
+
+        /* script returns a table */
+        } else if (lua_type(tluajit->luastate, 1) == LUA_TTABLE) {
+            lua_pushnil(tluajit->luastate);
+            const char *k, *v;
+            while (lua_next(tluajit->luastate, -2)) {
+                v = lua_tostring(tluajit->luastate, -1);
+                lua_pop(tluajit->luastate, 1);
+                k = lua_tostring(tluajit->luastate, -1);
+
+                if (!k || !v)
+                    continue;
+
+                SCLogDebug("k='%s', v='%s'", k, v);
+
+                if (strcmp(k, "retval") == 0) {
+                    if (atoi(v) == 1)
+                        ret = 1;
+                } else {
+                    /* set flow var? */
+                }
+            }
+
+            /* pop the table */
+            lua_pop(tluajit->luastate, 1);
+        }
+    }
+    while (lua_gettop(tluajit->luastate) > 0) {
+        lua_pop(tluajit->luastate, 1);
+    }
+
+    if (luajit->negated) {
+        if (ret == 1)
+            ret = 0;
+        else
+            ret = 1;
+    }
+
+    SCReturnInt(ret);
+}
+
 #ifdef UNITTESTS
 /* if this ptr is set the luajit setup functions will use this buffer as the
  * lua script instead of calling luaL_loadfile on the filename supplied. */