luajit: add flowint support

Expose ScFlowintGet and ScFlowintSet functions to luajit. These set
flowints in real time, regardless of rule and/or script match.

Example:

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

function match(args)
    a = ScFlowintGet(0);
    if a then
        ScFlowintSet(0, a + 1)
    else
        ScFlowintSet(0, 1)
    end

    a = ScFlowintGet(0);
    if a == 23 then
        return 1
    end

    return 0
end

return 0

Script's init call first registers "cnt" at id 0, then 0 is used to use
this var.
pull/378/head
Victor Julien 12 years ago
parent c3c3cd76e5
commit 72f6bc2aed

@ -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;
}

@ -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"
"<!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;
}
#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
}

@ -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;

Loading…
Cancel
Save