luajit/flowint: add ScFlowintIncr & ScFlowintDecr

Add flowint lua functions for incrementing and decrementing flowints.

First use creates the var and inits to 0. So a call:

    a = ScFlowintIncr(0)

Results in a == 1.

If the var reached UINT_MAX (2^32), it's not further incremented. If the
var reaches 0 it's not decremented further.

Calling ScFlowintDecr on a uninitialized var will init it to 0.

Example script:

    function init (args)
        local needs = {}
        needs["http.request_headers"] = tostring(true)
        needs["flowint"] = {"cnt_incr"}
        return needs
    end

    function match(args)
        a = ScFlowintIncr(0);
        if a == 23 then
            return 1
        end

        return 0
    end
    return 0

This script matches the 23rd time it's invoked on a flow.
pull/378/head
Victor Julien 12 years ago
parent f312486c6e
commit f29e5459e6

@ -304,7 +304,7 @@ static int LuajitGetFlowint(lua_State *luastate) {
lua_gettable(luastate, LUA_REGISTRYINDEX);
need_flow_lock = lua_toboolean(luastate, -1);
/* need flowvar idx */
/* need flowint idx */
if (!lua_isnumber(luastate, 1)) {
SCLogDebug("1st arg not a number");
lua_pushnil(luastate);
@ -315,14 +315,14 @@ static int LuajitGetFlowint(lua_State *luastate) {
if (id < 0 || id >= DETECT_LUAJIT_MAX_FLOWINTS) {
SCLogDebug("id %d", id);
lua_pushnil(luastate);
lua_pushstring(luastate, "flowvar id out of range");
lua_pushstring(luastate, "flowint 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");
lua_pushstring(luastate, "flowint id uninitialized");
return 2;
}
@ -345,7 +345,7 @@ static int LuajitGetFlowint(lua_State *luastate) {
if (need_flow_lock)
FLOWLOCK_UNLOCK(f);
/* return value through luastate, as a luastring */
/* return value through luastate, as a luanumber */
lua_pushnumber(luastate, (lua_Number)number);
SCLogDebug("retrieved flow:%p idx:%u value:%u", f, idx, number);
@ -400,7 +400,7 @@ int LuajitSetFlowint(lua_State *luastate) {
lua_gettable(luastate, LUA_REGISTRYINDEX);
need_flow_lock = lua_toboolean(luastate, -1);
/* need flowvar idx */
/* need flowint idx */
if (!lua_isnumber(luastate, 1)) {
lua_pushnil(luastate);
lua_pushstring(luastate, "1st arg not a number");
@ -409,7 +409,7 @@ int LuajitSetFlowint(lua_State *luastate) {
id = lua_tonumber(luastate, 1);
if (id < 0 || id >= DETECT_LUAJIT_MAX_FLOWVARS) {
lua_pushnil(luastate);
lua_pushstring(luastate, "flowvar id out of range");
lua_pushstring(luastate, "flowint id out of range");
return 2;
}
@ -442,6 +442,172 @@ int LuajitSetFlowint(lua_State *luastate) {
return 0;
}
static int LuajitIncrFlowint(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 flowint 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, "flowint id out of range");
return 2;
}
idx = ld->flowint[id];
if (idx == 0) {
SCLogDebug("idx %u", idx);
lua_pushnil(luastate);
lua_pushstring(luastate, "flowint id uninitialized");
return 2;
}
/* lookup var */
if (need_flow_lock)
FLOWLOCK_RDLOCK(f);
fv = FlowVarGet(f, idx);
if (fv == NULL) {
number = 1;
} else {
number = fv->data.fv_int.value;
if (number < UINT_MAX)
number++;
}
FlowVarAddIntNoLock(f, idx, number);
if (need_flow_lock)
FLOWLOCK_UNLOCK(f);
/* return value through luastate, as a luanumber */
lua_pushnumber(luastate, (lua_Number)number);
SCLogDebug("incremented flow:%p idx:%u value:%u", f, idx, number);
return 1;
}
static int LuajitDecrFlowint(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 flowint 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, "flowint id out of range");
return 2;
}
idx = ld->flowint[id];
if (idx == 0) {
SCLogDebug("idx %u", idx);
lua_pushnil(luastate);
lua_pushstring(luastate, "flowint id uninitialized");
return 2;
}
/* lookup var */
if (need_flow_lock)
FLOWLOCK_RDLOCK(f);
fv = FlowVarGet(f, idx);
if (fv == NULL) {
number = 0;
} else {
number = fv->data.fv_int.value;
if (number > 0)
number--;
}
FlowVarAddIntNoLock(f, idx, number);
if (need_flow_lock)
FLOWLOCK_UNLOCK(f);
/* return value through luastate, as a luanumber */
lua_pushnumber(luastate, (lua_Number)number);
SCLogDebug("decremented flow:%p idx:%u value:%u", f, idx, number);
return 1;
}
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);
@ -481,6 +647,13 @@ int LuajitRegisterExtensions(lua_State *lua_state) {
lua_pushcfunction(lua_state, LuajitSetFlowint);
lua_setglobal(lua_state, "ScFlowintSet");
lua_pushcfunction(lua_state, LuajitIncrFlowint);
lua_setglobal(lua_state, "ScFlowintIncr");
lua_pushcfunction(lua_state, LuajitDecrFlowint);
lua_setglobal(lua_state, "ScFlowintDecr");
return 0;
}

@ -1475,6 +1475,299 @@ end:
return result;
}
/** \test http buffer, flowints */
static int LuajitMatchTest05(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 = ScFlowintIncr(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"
"<!DOCTYPE html PUBLIC";
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
TcpSession ssn;
Packet *p1 = NULL;
Packet *p2 = NULL;
Flow f;
Signature *s = NULL;
ThreadVars th_v;
DetectEngineThreadCtx *det_ctx;
ut_script = script;
memset(&th_v, 0, sizeof(th_v));
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
FLOW_INITIALIZE(&f);
f.protoctx = (void *)&ssn;
f.flags |= FLOW_IPV4;
f.alproto = ALPROTO_HTTP;
p1->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;
}
/** \test http buffer, flowints */
static int LuajitMatchTest06(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 == nil then\n"
" print \"new var set to 2\""
" ScFlowintSet(0, 2)\n"
" end\n"
" a = ScFlowintDecr(0)\n"
" if a == 0 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"
"<!DOCTYPE html PUBLIC";
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
TcpSession ssn;
Packet *p1 = NULL;
Packet *p2 = NULL;
Flow f;
Signature *s = NULL;
ThreadVars th_v;
DetectEngineThreadCtx *det_ctx;
ut_script = script;
memset(&th_v, 0, sizeof(th_v));
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
FLOW_INITIALIZE(&f);
f.protoctx = (void *)&ssn;
f.flags |= FLOW_IPV4;
f.alproto = ALPROTO_HTTP;
p1->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 != 0) {
printf("%u != %u: ", fv->data.fv_int.value, 0);
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) {
@ -1483,6 +1776,8 @@ void DetectLuajitRegisterTests(void) {
UtRegisterTest("LuajitMatchTest02", LuajitMatchTest02, 1);
UtRegisterTest("LuajitMatchTest03", LuajitMatchTest03, 1);
UtRegisterTest("LuajitMatchTest04", LuajitMatchTest04, 1);
UtRegisterTest("LuajitMatchTest05", LuajitMatchTest05, 1);
UtRegisterTest("LuajitMatchTest06", LuajitMatchTest06, 1);
#endif
}

Loading…
Cancel
Save