diff --git a/src/detect-luajit-extensions.c b/src/detect-luajit-extensions.c index bc2db10a74..1f8bfea1ba 100644 --- a/src/detect-luajit-extensions.c +++ b/src/detect-luajit-extensions.c @@ -266,6 +266,180 @@ int LuajitSetFlowvar(lua_State *luastate) { return 0; } +static int LuajitGetFlowint(lua_State *luastate) { + uint16_t idx; + int id; + Flow *f; + FlowVar *fv; + DetectLuajitData *ld; + int need_flow_lock = 0; + uint32_t number; + + /* need luajit data for id -> idx conversion */ + lua_pushlightuserdata(luastate, (void *)&luaext_key_ld); + lua_gettable(luastate, LUA_REGISTRYINDEX); + ld = lua_touserdata(luastate, -1); + SCLogDebug("ld %p", ld); + if (ld == NULL) { + lua_pushnil(luastate); + lua_pushstring(luastate, "internal error: no ld"); + return 2; + } + + /* need flow */ + lua_pushlightuserdata(luastate, (void *)&luaext_key_flow); + lua_gettable(luastate, LUA_REGISTRYINDEX); + f = lua_touserdata(luastate, -1); + SCLogDebug("f %p", f); + if (f == NULL) { + lua_pushnil(luastate); + lua_pushstring(luastate, "no flow"); + return 2; + } + + /* need flow lock hint */ + lua_pushlightuserdata(luastate, (void *)&luaext_key_need_flow_lock); + lua_gettable(luastate, LUA_REGISTRYINDEX); + need_flow_lock = lua_toboolean(luastate, -1); + + /* need flowvar idx */ + if (!lua_isnumber(luastate, 1)) { + SCLogDebug("1st arg not a number"); + lua_pushnil(luastate); + lua_pushstring(luastate, "1st arg not a number"); + return 2; + } + id = lua_tonumber(luastate, 1); + if (id < 0 || id >= DETECT_LUAJIT_MAX_FLOWINTS) { + SCLogDebug("id %d", id); + lua_pushnil(luastate); + lua_pushstring(luastate, "flowvar id out of range"); + return 2; + } + idx = ld->flowint[id]; + if (idx == 0) { + SCLogDebug("idx %u", idx); + lua_pushnil(luastate); + lua_pushstring(luastate, "flowvar id uninitialized"); + return 2; + } + + /* lookup var */ + if (need_flow_lock) + FLOWLOCK_RDLOCK(f); + + fv = FlowVarGet(f, idx); + if (fv == NULL) { + SCLogDebug("fv NULL"); + if (need_flow_lock) + FLOWLOCK_UNLOCK(f); + + lua_pushnil(luastate); + lua_pushstring(luastate, "no flow var"); + return 2; + } + number = fv->data.fv_int.value; + + if (need_flow_lock) + FLOWLOCK_UNLOCK(f); + + /* return value through luastate, as a luastring */ + lua_pushnumber(luastate, (lua_Number)number); + SCLogDebug("retrieved flow:%p idx:%u value:%u", f, idx, number); + + return 1; + +} + +int LuajitSetFlowint(lua_State *luastate) { + uint16_t idx; + int id; + Flow *f; + DetectEngineThreadCtx *det_ctx; + DetectLuajitData *ld; + int need_flow_lock = 0; + uint32_t number; + lua_Number luanumber; + + /* need luajit data for id -> idx conversion */ + lua_pushlightuserdata(luastate, (void *)&luaext_key_ld); + lua_gettable(luastate, LUA_REGISTRYINDEX); + ld = lua_touserdata(luastate, -1); + SCLogDebug("ld %p", ld); + if (ld == NULL) { + lua_pushnil(luastate); + lua_pushstring(luastate, "internal error: no ld"); + return 2; + } + + /* need det_ctx */ + lua_pushlightuserdata(luastate, (void *)&luaext_key_det_ctx); + lua_gettable(luastate, LUA_REGISTRYINDEX); + det_ctx = lua_touserdata(luastate, -1); + SCLogDebug("det_ctx %p", det_ctx); + if (det_ctx == NULL) { + lua_pushnil(luastate); + lua_pushstring(luastate, "internal error: no det_ctx"); + return 2; + } + + /* need flow */ + lua_pushlightuserdata(luastate, (void *)&luaext_key_flow); + lua_gettable(luastate, LUA_REGISTRYINDEX); + f = lua_touserdata(luastate, -1); + SCLogDebug("f %p", f); + if (f == NULL) { + lua_pushnil(luastate); + lua_pushstring(luastate, "no flow"); + return 2; + } + /* need flow lock hint */ + lua_pushlightuserdata(luastate, (void *)&luaext_key_need_flow_lock); + lua_gettable(luastate, LUA_REGISTRYINDEX); + need_flow_lock = lua_toboolean(luastate, -1); + + /* need flowvar idx */ + if (!lua_isnumber(luastate, 1)) { + lua_pushnil(luastate); + lua_pushstring(luastate, "1st arg not a number"); + return 2; + } + id = lua_tonumber(luastate, 1); + if (id < 0 || id >= DETECT_LUAJIT_MAX_FLOWVARS) { + lua_pushnil(luastate); + lua_pushstring(luastate, "flowvar id out of range"); + return 2; + } + + if (!lua_isnumber(luastate, 2)) { + lua_pushnil(luastate); + lua_pushstring(luastate, "2nd arg not a number"); + return 2; + } + luanumber = lua_tonumber(luastate, 2); + if (luanumber < 0 || id > (double)UINT_MAX) { + lua_pushnil(luastate); + lua_pushstring(luastate, "value out of range, value must be unsigned 32bit int"); + return 2; + } + number = (uint32_t)luanumber; + + idx = ld->flowint[id]; + if (idx == 0) { + lua_pushnil(luastate); + lua_pushstring(luastate, "flowint id uninitialized"); + return 2; + } + + if (need_flow_lock) + FlowVarAddInt(f, idx, number); + else + FlowVarAddIntNoLock(f, idx, number); + + SCLogDebug("stored flow:%p idx:%u value:%u", f, idx, number); + return 0; +} + void LuajitExtensionsMatchSetup(lua_State *lua_state, DetectLuajitData *ld, DetectEngineThreadCtx *det_ctx, Flow *f, int need_flow_lock) { SCLogDebug("det_ctx %p, f %p", det_ctx, f); @@ -299,6 +473,12 @@ int LuajitRegisterExtensions(lua_State *lua_state) { lua_pushcfunction(lua_state, LuajitSetFlowvar); lua_setglobal(lua_state, "ScFlowvarSet"); + + lua_pushcfunction(lua_state, LuajitGetFlowint); + lua_setglobal(lua_state, "ScFlowintGet"); + + lua_pushcfunction(lua_state, LuajitSetFlowint); + lua_setglobal(lua_state, "ScFlowintSet"); return 0; } diff --git a/src/detect-luajit.c b/src/detect-luajit.c index 26c1e6e3ad..0299fce519 100644 --- a/src/detect-luajit.c +++ b/src/detect-luajit.c @@ -674,6 +674,28 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuajitData *ld) { } lua_pop(luastate, 1); continue; + } else if (strcmp(k, "flowint") == 0) { + if (lua_istable(luastate, -1)) { + lua_pushnil(luastate); + while (lua_next(luastate, -2) != 0) { + /* value at -1, key is at -2 which we ignore */ + const char *value = lua_tostring(luastate, -1); + SCLogDebug("value %s", value); + /* removes 'value'; keeps 'key' for next iteration */ + lua_pop(luastate, 1); + + if (ld->flowints == DETECT_LUAJIT_MAX_FLOWINTS) { + SCLogError(SC_ERR_LUAJIT_ERROR, "too many flowints registered"); + goto error; + } + + uint16_t idx = VariableNameGetIdx(de_ctx, (char *)value, DETECT_FLOWINT); + ld->flowint[ld->flowints++] = idx; + SCLogDebug("script uses flowint %u with script id %u", idx, ld->flowints - 1); + } + } + lua_pop(luastate, 1); + continue; } v = lua_tostring(luastate, -1); @@ -1301,6 +1323,158 @@ end: UTHFreePackets(&p2, 1); return result; } + +/** \test http buffer, flowints */ +static int LuajitMatchTest04(void) { + const char script[] = + "function init (args)\n" + " local needs = {}\n" + " needs[\"http.request_headers\"] = tostring(true)\n" + " needs[\"flowint\"] = {\"cnt\"}\n" + " return needs\n" + "end\n" + "\n" + "function match(args)\n" + " print \"inspecting\"" + " a = ScFlowintGet(0)\n" + " if a then\n" + " ScFlowintSet(0, a + 1)\n" + " else\n" + " ScFlowintSet(0, 1)\n" + " end\n" + " \n" + " a = ScFlowintGet(0)\n" + " if a == 2 then\n" + " print \"match\"\n" + " return 1\n" + " end\n" + " return 0\n" + "end\n" + "return 0\n"; + char sig[] = "alert http any any -> any any (flow:to_server; luajit:unittest; sid:1;)"; + int result = 0; + uint8_t httpbuf1[] = + "POST / HTTP/1.1\r\n" + "Host: www.emergingthreats.net\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.13) Gecko/2009080315 Ubuntu/8.10 (intrepid) Firefox/3.0.13\r\n" + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8\r\n"; + uint8_t httpbuf2[] = + "Accept-Language: es-es,es;q=0.8,en-us;q=0.5,en;q=0.3\r\n" + "Accept-Encoding: gzip,deflate\r\n" + "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" + "Date: Tue, 22 Sep 2009 19:24:48 GMT\r\n" + "Server: Apache\r\n" + "Content-Length: 500\r\n" + "\r\n" + "flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, sig); + if (s == NULL) { + printf("sig parse failed: "); + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + goto end; + } + HtpState *http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect for p1 */ + SCLogInfo("p1"); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched on p1 but should not have: "); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + if (r != 0) { + printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); + goto end; + } + /* do detect for p2 */ + SCLogInfo("p2"); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!(PacketAlertCheck(p2, 1))) { + printf("sid 1 didn't match on p2 but should have: "); + goto end; + } + + FlowVar *fv = FlowVarGet(&f, 1); + if (fv == NULL) { + printf("no flowvar: "); + goto end; + } + + if (fv->data.fv_int.value != 2) { + printf("%u != %u: ", fv->data.fv_int.value, 2); + goto end; + } + + result = 1; +end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + #endif void DetectLuajitRegisterTests(void) { @@ -1308,6 +1482,7 @@ void DetectLuajitRegisterTests(void) { UtRegisterTest("LuajitMatchTest01", LuajitMatchTest01, 1); UtRegisterTest("LuajitMatchTest02", LuajitMatchTest02, 1); UtRegisterTest("LuajitMatchTest03", LuajitMatchTest03, 1); + UtRegisterTest("LuajitMatchTest04", LuajitMatchTest04, 1); #endif } diff --git a/src/detect-luajit.h b/src/detect-luajit.h index ad14d7a3a7..6d23452a09 100644 --- a/src/detect-luajit.h +++ b/src/detect-luajit.h @@ -37,6 +37,7 @@ typedef struct DetectLuajitThreadData { } DetectLuajitThreadData; #define DETECT_LUAJIT_MAX_FLOWVARS 15 +#define DETECT_LUAJIT_MAX_FLOWINTS 15 typedef struct DetectLuajitData { int thread_ctx_id; @@ -45,6 +46,8 @@ typedef struct DetectLuajitData { uint32_t flags; int alproto; char *buffername; /* buffer name in case of a single buffer */ + uint16_t flowint[DETECT_LUAJIT_MAX_FLOWINTS]; + uint16_t flowints; uint16_t flowvar[DETECT_LUAJIT_MAX_FLOWVARS]; uint16_t flowvars; } DetectLuajitData;