diff --git a/src/detect-lua.c b/src/detect-lua.c index 75364136ff..04d7394f95 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -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. */