diff --git a/lua/zapret-lib.lua b/lua/zapret-lib.lua index 07233ad..ad42878 100644 --- a/lua/zapret-lib.lua +++ b/lua/zapret-lib.lua @@ -37,6 +37,29 @@ function pktdebug(ctx, desync) end +-- copy instance identification and args from execution plan to desync table +function apply_execution_plan(desync, plan) + desync.func = plan.func + desync.func_n = plan.func_n + desync.func_instance = plan.func_instance + desync.arg = plan.arg +end +-- this function demonstrates how to stop execution of upcoming desync instances and take over their job +-- this can be used, for example, for orchestrating conditional processing without modifying of desync functions code +-- test case : nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-desync=desync_orchestrator_example --lua-desync=pass --lua-desync=pass +function desync_orchestrator_example(ctx, desync) + local plan = execution_plan(ctx) + if #plan>0 then + DLOG("orchestrator: taking over upcoming desync instances") + local desync_copy = deepcopy(desync) + execution_plan_cancel(ctx) + for i=1,#plan do + apply_execution_plan(desync_copy, plan[i]) + DLOG("orchestrator: executing '"..desync_copy.func_instance.."'") + _G[plan[i].func](ctx, desync_copy) + end + end +end -- prepare standard rawsend options from desync -- repeats - how many time send the packet @@ -1031,4 +1054,3 @@ function ipfrag2(dis, ipfrag_options) return {dis1,dis2} end - diff --git a/nfq2/desync.c b/nfq2/desync.c index c7b0094..e5e7890 100644 --- a/nfq2/desync.c +++ b/nfq2/desync.c @@ -638,10 +638,6 @@ err: lua_pop(params.L, rescount); return false; } -static void desync_instance(const char *func, unsigned int dp_n, unsigned int func_n, char *instance, size_t inst_size) -{ - snprintf(instance, inst_size, "%s_%u_%u", func, dp_n, func_n); -} static uint8_t desync( struct desync_profile *dp, uint32_t fwmark, @@ -659,7 +655,7 @@ static uint8_t desync( struct func_list *func; int ref_arg = LUA_NOREF, status; bool b, b_cutoff_all, b_unwanted_payload; - t_lua_desync_context ctx = { .dp = dp, .ctrack = ctrack, .dis = dis }; + t_lua_desync_context ctx = { .dp = dp, .ctrack = ctrack, .dis = dis, .cancel = false }; const char *sDirection = bIncoming ? "in" : "out"; struct packet_range *range; size_t l; @@ -681,14 +677,12 @@ static uint8_t desync( } if (LIST_FIRST(&dp->lua_desync)) { - unsigned int func_n; - b_cutoff_all = b_unwanted_payload = true; - func_n = 1; + ctx.func_n = 1; LIST_FOREACH(func, &dp->lua_desync, next) { ctx.func = func->func; - desync_instance(func->func, dp->n, func_n, instance, sizeof(instance)); + desync_instance(func->func, dp->n, ctx.func_n, instance, sizeof(instance)); ctx.instance = instance; range = bIncoming ? &func->range_in : &func->range_out; @@ -713,7 +707,7 @@ static uint8_t desync( else b_cutoff_all = false; } - func_n++; + ctx.func_n++; } if (b_cutoff_all) { @@ -755,11 +749,11 @@ static uint8_t desync( } ref_arg = luaL_ref(params.L, LUA_REGISTRYINDEX); - func_n = 1; + ctx.func_n = 1; LIST_FOREACH(func, &dp->lua_desync, next) { ctx.func = func->func; - desync_instance(func->func, dp->n, func_n, instance, sizeof(instance)); + desync_instance(func->func, dp->n, ctx.func_n, instance, sizeof(instance)); ctx.instance = instance; if (!lua_instance_cutoff_check(&ctx, bIncoming)) @@ -789,7 +783,7 @@ static uint8_t desync( lua_rawgeti(params.L, LUA_REGISTRYINDEX, ref_arg); lua_pushf_args(&func->args, -1); lua_pushf_str("func", func->func); - lua_pushf_int("func_n", func_n); + lua_pushf_int("func_n", ctx.func_n); lua_pushf_str("func_instance", instance); int initial_stack_top = lua_gettop(params.L); status = lua_pcall(params.L, 2, LUA_MULTRET, 0); @@ -808,37 +802,6 @@ static uint8_t desync( case VERDICT_DROP: verdict = VERDICT_DROP; } - - if (ctrack) - { - // lua cutoff - lua_rawgeti(params.L, LUA_REGISTRYINDEX, ref_arg); - lua_getfield(params.L, -1, "track"); - if (lua_istable(params.L, -1)) - { - if (!ctrack->b_lua_in_cutoff) - { - lua_getfield(params.L, -1, "lua_in_cutoff"); - if (lua_toboolean(params.L, -1)) - { - ctrack->b_lua_in_cutoff = true; - DLOG("* lua in cutoff set\n"); - } - lua_pop(params.L, 1); - } - if (!ctrack->b_lua_out_cutoff) - { - lua_getfield(params.L, -1, "lua_out_cutoff"); - if (lua_toboolean(params.L, -1)) - { - ctrack->b_lua_out_cutoff = true; - DLOG("* lua out cutoff set\n"); - } - lua_pop(params.L, 1); - } - } - lua_pop(params.L, 2); - } } else DLOG("* lua '%s' : payload_type '%s' does not satisfy filter\n", instance, l7payload_str(l7payload)); @@ -852,7 +815,8 @@ static uint8_t desync( range->upper_cutoff ? '<' : '-', range->to.mode, range->to.pos); } - func_n++; + if (ctx.cancel) break; + ctx.func_n++; } } diff --git a/nfq2/lua.c b/nfq2/lua.c index 476ed15..72b9172 100644 --- a/nfq2/lua.c +++ b/nfq2/lua.c @@ -19,6 +19,11 @@ #include "crypto/aes-ctr.h" +void desync_instance(const char *func, unsigned int dp_n, unsigned int func_n, char *instance, size_t inst_size) +{ + snprintf(instance, inst_size, "%s_%u_%u", func, dp_n, func_n); +} + static void lua_check_argc(lua_State *L, const char *where, int argc) { int num_args = lua_gettop(L); @@ -639,7 +644,7 @@ static int luacall_instance_cutoff(lua_State *L) int argc=lua_gettop(L); bool bIn,bOut; - if (argc>=2) + if (argc>=2 && lua_type(L,2)!=LUA_TNIL) { luaL_checktype(L,2,LUA_TBOOLEAN); bOut = lua_toboolean(L,2); @@ -705,6 +710,94 @@ bool lua_instance_cutoff_check(const t_lua_desync_context *ctx, bool bIn) return b; } +static int luacall_lua_cutoff(lua_State *L) +{ + lua_check_argc_range(L,"lua_cutoff",1,2); + + LUA_STACK_GUARD_ENTER(L) + + t_lua_desync_context *ctx; + + if (!lua_islightuserdata(L,1)) + luaL_error(L, "lua_cutoff expect desync context in the first argument"); + ctx = lua_touserdata(L,1); + + int argc=lua_gettop(L); + bool bIn,bOut; + if (argc>=2 && lua_type(L,2)!=LUA_TNIL) + { + luaL_checktype(L,2,LUA_TBOOLEAN); + bOut = lua_toboolean(L,2); + bIn = !bOut; + } + else + bIn = bOut = true; + + if (ctx->ctrack) + { + DLOG("lua cutoff from '%s' in=%u out=%u\n",ctx->instance,bIn,bOut); + // lua cutoff is one way transition + if (bIn) ctx->ctrack->b_lua_in_cutoff = true; + if (bOut) ctx->ctrack->b_lua_out_cutoff = true; + } + else + DLOG("lua cutoff requested from '%s' in=%u out=%u but not possible without conntrack\n",ctx->instance,bIn,bOut); + + LUA_STACK_GUARD_RETURN(L,0) +} + +static int luacall_execution_plan(lua_State *L) +{ + lua_check_argc(L,"execution_plan",1); + + LUA_STACK_GUARD_ENTER(L) + + const t_lua_desync_context *ctx; + + if (!lua_islightuserdata(L,1)) + luaL_error(L, "execution_plan expect desync context in the first argument"); + ctx = lua_touserdata(L,1); + + lua_newtable(L); + + struct func_list *func; + char instance[256]; + unsigned int n=1; + LIST_FOREACH(func, &ctx->dp->lua_desync, next) + { + if (n > ctx->func_n) + { + desync_instance(func->func, ctx->dp->n, n, instance, sizeof(instance)); + lua_pushinteger(params.L, n - ctx->func_n); + lua_createtable(params.L, 0, 4); + lua_pushf_str("func", func->func); + lua_pushf_int("func_n", ctx->func_n); + lua_pushf_str("func_instance", instance); + lua_pushf_args(&func->args, -1); + lua_rawset(params.L,-3); + } + n++; + } + + LUA_STACK_GUARD_RETURN(L,1) +} +static int luacall_execution_plan_cancel(lua_State *L) +{ + lua_check_argc(L,"execution_plan_cancel",1); + + t_lua_desync_context *ctx; + + if (!lua_islightuserdata(L,1)) + luaL_error(L, "execution_plan_cancel expect desync context in the first argument"); + ctx = lua_touserdata(L,1); + + DLOG("execution plan cancel from '%s'\n",ctx->instance); + + ctx->cancel = true; + return 0; +} + + static int luacall_raw_packet(lua_State *L) { lua_check_argc(L,"raw_packet",1); @@ -2836,6 +2929,12 @@ static void lua_init_functions(void) // voluntarily stop receiving packets {"instance_cutoff",luacall_instance_cutoff}, + // voluntarily stop receiving packets of the current connection for all instances + {"lua_cutoff",luacall_lua_cutoff}, + // get info about upcoming desync instances and their arguments + {"execution_plan",luacall_execution_plan}, + // cancel execution of upcoming desync instances and their arguments + {"execution_plan_cancel",luacall_execution_plan_cancel}, // get raw packet data {"raw_packet",luacall_raw_packet}, diff --git a/nfq2/lua.h b/nfq2/lua.h index fd694ef..2f4f0a9 100644 --- a/nfq2/lua.h +++ b/nfq2/lua.h @@ -28,6 +28,9 @@ #define LUA_STACK_GUARD_RETURN(L,N) LUA_STACK_GUARD_LEAVE(L,N); return N; +void desync_instance(const char *func, unsigned int dp_n, unsigned int func_n, char *instance, size_t inst_size); + + bool lua_test_init_script_files(void); bool lua_init(void); void lua_shutdown(void); @@ -79,10 +82,12 @@ bool lua_reconstruct_udphdr(int idx, struct udphdr *udp); bool lua_reconstruct_dissect(int idx, uint8_t *buf, size_t *len, bool badsum, bool ip6_preserve_next); typedef struct { + unsigned int func_n; const char *func, *instance; const struct desync_profile *dp; - const t_ctrack *ctrack; const struct dissect *dis; + t_ctrack *ctrack; + bool cancel; } t_lua_desync_context; bool lua_instance_cutoff_check(const t_lua_desync_context *ctx, bool bIn);