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);
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;
}
}
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);
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) {
UtRegisterTest("LuajitMatchTest01", LuajitMatchTest01, 1);
UtRegisterTest("LuajitMatchTest02", LuajitMatchTest02, 1);
UtRegisterTest("LuajitMatchTest03", LuajitMatchTest03, 1);
+ UtRegisterTest("LuajitMatchTest04", LuajitMatchTest04, 1);
#endif
}
} DetectLuajitThreadData;
#define DETECT_LUAJIT_MAX_FLOWVARS 15
+#define DETECT_LUAJIT_MAX_FLOWINTS 15
typedef struct DetectLuajitData {
int thread_ctx_id;
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;