From 6010307667e741b5c65050e7d65531a0be804c78 Mon Sep 17 00:00:00 2001 From: bol-van Date: Tue, 2 Dec 2025 20:47:52 +0300 Subject: [PATCH] nfqws2: post payload filter and range in exec plan, zapret-lib: duplicate range check logic --- lua/zapret-lib.lua | 84 ++++++++++++++++++++++++++++++++++++++++------ nfq2/desync.c | 2 +- nfq2/lua.c | 40 ++++++++++++++++++++-- nfq2/lua.h | 4 ++- nfq2/nfqws.c | 1 + nfq2/protocol.c | 29 ++++++++++++++++ nfq2/protocol.h | 1 + 7 files changed, 146 insertions(+), 15 deletions(-) diff --git a/lua/zapret-lib.lua b/lua/zapret-lib.lua index ad42878..cc901d6 100644 --- a/lua/zapret-lib.lua +++ b/lua/zapret-lib.lua @@ -54,13 +54,73 @@ function desync_orchestrator_example(ctx, desync) 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) + if not payload_match_filter(desync.l7payload, plan[i].payload_filter) then + DLOG("orchestrator: not calling '"..desync_copy.func_instance.."' because payload '"..desync.l7payload.."' does not match filter '"..plan[i].payload_filter.."'") + elseif not pos_check_range(desync, plan[i].range) then + DLOG("orchestrator: not calling '"..desync_copy.func_instance.."' because pos "..pos_str(desync,plan[i].range.from).." "..pos_str(desync,plan[i].range.to).." is out of range '"..pos_range_str(plan[i].range).."'") + else + apply_execution_plan(desync_copy, plan[i]) + DLOG("orchestrator: executing '"..desync_copy.func_instance.."'") + _G[plan[i].func](ctx, desync_copy) + end end end end +-- these function duplicate range check logic from C code +-- mode must be n,d,b,s,x,a +-- pos is {mode,pos} +-- range is {from={mode,pos}, to={mode,pos}, upper_cutoff} +-- upper_cutoff = true means non-inclusive upper boundary +function pos_get(desync, mode) + if desync.track then + if mode=='n' then + return desync.outgoing and desync.track.pcounter_orig or desync.track.pcounter_reply + elseif mode=='d' then + return desync.outgoing and desync.track.pdcounter_orig or desync.track.pdcounter_reply + elseif mode=='b' then + return desync.outgoing and desync.track.pbcounter_orig or desync.track.pbcounter_reply + elseif mode=='s' and desync.track.tcp then + return desync.outgoing and (desync.track.tcp.seq - desync.track.tcp.seq0) or (desync.track.tcp.ack - desync.track.tcp.ack0) + end + end + return 0 +end +function pos_check_from(desync, range) + if range.from.mode == 'x' then return false end + if range.from.mode ~= 'a' then + if desync.track then + return pos_get(desync, range.from.mode) >= range.from.pos + else + return false + end + end + return true; +end +function pos_check_to(desync, range) + local ps + if range.to.mode == 'x' then return false end + if range.to.mode ~= 'a' then + if desync.track then + ps = pos_get(desync, range.to.mode) + return (ps < range.to.pos) or not range.upper_cutoff and (ps == range.to.pos) + else + return false + end + end + return true; +end +function pos_check_range(desync, range) + return pos_check_from(desync,range) and pos_check_to(desync,range) +end +function pos_range_str(range) + return range.from.mode..range.from.pos..(range.upper_cutoff and '<' or '-')..range.to.mode..range.to.pos +end +function pos_str(desync, pos) + return pos.mode..pos_get(desync, pos.mode) +end + + -- prepare standard rawsend options from desync -- repeats - how many time send the packet -- ifout - override outbound interface (if --bind_fix4, --bind-fix6 enabled) @@ -825,17 +885,21 @@ function direction_cutoff_opposite(ctx, desync, def) instance_cutoff(ctx, true) end end + +-- return true if l7payload matches filter l7payload_filter - comma separated list of payload types +function payload_match_filter(l7payload, l7payload_filter, def) + local argpl = l7payload_filter or def or "known" + local neg = string.sub(argpl,1,1)=="~" + local pl = neg and string.sub(argpl,2) or argpl + return neg ~= (in_list(pl, "all") or in_list(pl, l7payload) or in_list(pl, "known") and l7payload~="unknown" and l7payload~="empty") +end -- check if desync payload type comply with payload type list in arg.payload -- if arg.payload is not present - check for known payload - not empty and not unknown (nfqws1 behavior without "--desync-any-protocol" option) -- if arg.payload is prefixed with '~' - it means negation function payload_check(desync, def) - local b - local argpl = desync.arg.payload or def or "known" - local neg = string.sub(argpl,1,1)=="~" - local pl = neg and string.sub(argpl,2) or argpl - - b = neg ~= (in_list(pl, "all") or in_list(pl, desync.l7payload) or in_list(pl, "known") and desync.l7payload~="unknown" and desync.l7payload~="empty") - if not b then + local b = payload_match_filter(desync.l7payload, desync.arg.payload, def) + if not b and b_debug then + local argpl = desync.arg.payload or def or "known" DLOG("payload_check: payload '"..desync.l7payload.."' does not pass '"..argpl.."' filter") end return b diff --git a/nfq2/desync.c b/nfq2/desync.c index e5e7890..9e2496f 100644 --- a/nfq2/desync.c +++ b/nfq2/desync.c @@ -655,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, .cancel = false }; + t_lua_desync_context ctx = { .dp = dp, .ctrack = ctrack, .dis = dis, .cancel = false, .incoming = bIncoming }; const char *sDirection = bIncoming ? "in" : "out"; struct packet_range *range; size_t l; diff --git a/nfq2/lua.c b/nfq2/lua.c index 72b9172..abead75 100644 --- a/nfq2/lua.c +++ b/nfq2/lua.c @@ -761,19 +761,27 @@ static int luacall_execution_plan(lua_State *L) lua_newtable(L); struct func_list *func; - char instance[256]; + char instance[256], pls[2048]; + struct packet_range *range; 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)); + range = ctx->incoming ? &func->range_in : &func->range_out; lua_pushinteger(params.L, n - ctx->func_n); - lua_createtable(params.L, 0, 4); + lua_createtable(params.L, 0, 6); + lua_pushf_args(&func->args, -1); 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_pushf_range("range", range); + if (l7_payload_str_list(func->payload_type, pls, sizeof(pls))) + lua_pushf_str("payload_filter", pls); + else + lua_pushf_nil("payload_filter"); + lua_rawset(params.L,-3); } n++; @@ -1253,7 +1261,33 @@ void lua_pushf_args(const struct ptr_list_head *args, int idx_desync) LUA_STACK_GUARD_LEAVE(params.L, 0) } +void lua_pushf_pos(const char *name, const struct packet_pos *pos) +{ + LUA_STACK_GUARD_ENTER(params.L) + char smode[2]="?"; + lua_pushf_table(name); + lua_getfield(params.L,-1,name); + *smode=pos->mode; + lua_pushf_str("mode",smode); + lua_pushf_int("pos",pos->pos); + lua_pop(params.L,1); + + LUA_STACK_GUARD_LEAVE(params.L, 0) +} +void lua_pushf_range(const char *name, const struct packet_range *range) +{ + LUA_STACK_GUARD_ENTER(params.L) + + lua_pushf_table(name); + lua_getfield(params.L,-1,"range"); + lua_pushf_bool("upper_cutoff",range->upper_cutoff); + lua_pushf_pos("from", &range->from); + lua_pushf_pos("to", &range->to); + lua_pop(params.L,1); + + LUA_STACK_GUARD_LEAVE(params.L, 0) +} static void lua_reconstruct_extract_options(lua_State *L, int idx, bool *badsum, bool *ip6_preserve_next, uint8_t *ip6_last_proto) diff --git a/nfq2/lua.h b/nfq2/lua.h index 2f4f0a9..b3ec0a9 100644 --- a/nfq2/lua.h +++ b/nfq2/lua.h @@ -73,6 +73,8 @@ void lua_push_dissect(const struct dissect *dis); void lua_pushf_dissect(const struct dissect *dis); void lua_pushf_ctrack(const t_ctrack *ctrack); void lua_pushf_args(const struct ptr_list_head *args, int idx_desync); +void lua_pushf_pos(const char *name, const struct packet_pos *pos); +void lua_pushf_range(const char *name, const struct packet_range *range); void lua_pushf_global(const char *field, const char *global); bool lua_reconstruct_ip6hdr(int idx, struct ip6_hdr *ip6, size_t *len, uint8_t last_proto, bool preserve_next); @@ -87,7 +89,7 @@ typedef struct { const struct desync_profile *dp; const struct dissect *dis; t_ctrack *ctrack; - bool cancel; + bool incoming,cancel; } t_lua_desync_context; bool lua_instance_cutoff_check(const t_lua_desync_context *ctx, bool bIn); diff --git a/nfq2/nfqws.c b/nfq2/nfqws.c index 26d9a96..33be666 100644 --- a/nfq2/nfqws.c +++ b/nfq2/nfqws.c @@ -1683,6 +1683,7 @@ int main(int argc, char **argv) { if (argc < 2) exithelp(); + aes_init_keygen_tables(); // required for aes set_console_io_buffering(); set_env_exedir(argv[0]); diff --git a/nfq2/protocol.c b/nfq2/protocol.c index 43e0f90..6bb2861 100644 --- a/nfq2/protocol.c +++ b/nfq2/protocol.c @@ -66,6 +66,35 @@ bool l7_payload_match(t_l7payload l7payload, uint64_t filter_l7p) { return filter_l7p==L7P_ALL || (filter_l7p & (1<L7P_KNOWN && l7payload