Template
1
0
mirror of https://github.com/bol-van/zapret2.git synced 2026-03-13 22:03:09 +00:00

nfqws2,zapret-auto: circular orchestrator

This commit is contained in:
bol-van
2025-12-06 15:58:09 +03:00
parent 2a7b44b1d0
commit 813fece07a
9 changed files with 387 additions and 69 deletions

View File

@@ -54,3 +54,5 @@ v0.4
v0.5
* nfqws2: u8add,u16add,u24add,u32add luacalls
* nfqws2: abandon any arithmetics beyond 32bit (because lua 5.1 does not support 64 bit integers, store everything as double)
* zapret-lib: http_reply, url and nld dissectors
* zapret-auto: circular orchestrator

View File

@@ -41,7 +41,7 @@ PIDDIR=/var/run
USEROPT="--user=$WS_USER"
NFQWS2="${NFQWS2:-$ZAPRET_BASE/nfq2/nfqws2}"
LUAOPT="--lua-init=@$ZAPRET_BASE/lua/zapret-lib.lua --lua-init=@$ZAPRET_BASE/lua/zapret-antidpi.lua"
LUAOPT="--lua-init=@$ZAPRET_BASE/lua/zapret-lib.lua --lua-init=@$ZAPRET_BASE/lua/zapret-antidpi.lua --lua-init=@$ZAPRET_BASE/lua/zapret-auto.lua"
NFQWS2_OPT_BASE="$USEROPT --fwmark=$DESYNC_MARK $LUAOPT"
run_daemon()

View File

@@ -72,7 +72,7 @@ DESYNC_MARK_POSTNAT=${DESYNC_MARK_POSTNAT:-0x20000000}
QNUM=${QNUM:-300}
NFQWS2="${NFQWS2:-$ZAPRET_BASE/nfq2/nfqws2}"
LUAOPT="--lua-init=@$ZAPRET_BASE/lua/zapret-lib.lua --lua-init=@$ZAPRET_BASE/lua/zapret-antidpi.lua"
LUAOPT="--lua-init=@$ZAPRET_BASE/lua/zapret-lib.lua --lua-init=@$ZAPRET_BASE/lua/zapret-antidpi.lua --lua-init=@$ZAPRET_BASE/lua/zapret-auto.lua"
NFQWS2_OPT_BASE="$USEROPT --fwmark=$DESYNC_MARK $LUAOPT"

View File

@@ -113,7 +113,7 @@ end
-- standard args : direction
function http_domcase(ctx, desync)
if not desync.dis.tcp then
instance_cutoff(ctx)
instance_cutoff_shim(ctx, desync)
return
end
direction_cutoff_opposite(ctx, desync)
@@ -139,7 +139,7 @@ end
-- arg : spell=<str> . spelling of the "Host" header. must be exactly 4 chars long
function http_hostcase(ctx, desync)
if not desync.dis.tcp then
instance_cutoff(ctx)
instance_cutoff_shim(ctx, desync)
return
end
direction_cutoff_opposite(ctx, desync)
@@ -164,7 +164,7 @@ end
-- standard args : direction
function http_methodeol(ctx, desync)
if not desync.dis.tcp then
instance_cutoff(ctx)
instance_cutoff_shim(ctx, desync)
return
end
direction_cutoff_opposite(ctx, desync)
@@ -221,10 +221,10 @@ function synack_split(ctx, desync)
error("synack_split: bad mode '"..mode.."'")
end
else
instance_cutoff(ctx) -- mission complete
instance_cutoff_shim(ctx, desync) -- mission complete
end
else
instance_cutoff(ctx)
instance_cutoff_shim(ctx, desync)
end
end
@@ -238,10 +238,10 @@ function synack(ctx, desync)
DLOG("synack: sending")
rawsend_dissect_ipfrag(dis, desync_opts(desync))
else
instance_cutoff(ctx) -- mission complete
instance_cutoff_shim(ctx, desync) -- mission complete
end
else
instance_cutoff(ctx)
instance_cutoff_shim(ctx, desync)
end
end
@@ -256,10 +256,10 @@ function wsize(ctx, desync)
return VERDICT_MODIFY
end
else
instance_cutoff(ctx) -- mission complete
instance_cutoff_shim(ctx, desync) -- mission complete
end
else
instance_cutoff(ctx)
instance_cutoff_shim(ctx, desync)
end
end
@@ -270,7 +270,7 @@ end
-- arg : forced_cutoff=<list> - comma separated list of payloads that trigger forced wssize cutoff. by default - any non-empty payload
function wssize(ctx, desync)
if not desync.dis.tcp then
instance_cutoff(ctx)
instance_cutoff_shim(ctx, desync)
return
end
local verdict = VERDICT_PASS
@@ -281,7 +281,7 @@ function wssize(ctx, desync)
end
if #desync.dis.payload>0 and (not desync.arg.forced_cutoff or in_list(desync.arg.forced_cutoff, desync.l7payload)) then
DLOG("wssize: forced cutoff")
instance_cutoff(ctx)
instance_cutoff_shim(ctx, desync)
end
end
return verdict
@@ -305,10 +305,10 @@ function syndata(ctx, desync)
return VERDICT_DROP
end
else
instance_cutoff(ctx) -- mission complete
instance_cutoff_shim(ctx, desync) -- mission complete
end
else
instance_cutoff(ctx)
instance_cutoff_shim(ctx, desync)
end
end
@@ -317,7 +317,7 @@ end
-- arg : rstack - send RST,ACK instead of RST
function rst(ctx, desync)
if not desync.dis.tcp then
instance_cutoff(ctx)
instance_cutoff_shim(ctx, desync)
return
end
direction_cutoff_opposite(ctx, desync)
@@ -371,7 +371,7 @@ end
-- arg : nodrop - do not drop current dissect
function multisplit(ctx, desync)
if not desync.dis.tcp then
instance_cutoff(ctx)
instance_cutoff_shim(ctx, desync)
return
end
direction_cutoff_opposite(ctx, desync)
@@ -425,7 +425,7 @@ end
-- arg : nodrop - do not drop current dissect
function multidisorder(ctx, desync)
if not desync.dis.tcp then
instance_cutoff(ctx)
instance_cutoff_shim(ctx, desync)
return
end
direction_cutoff_opposite(ctx, desync)
@@ -491,7 +491,7 @@ end
-- arg : nodrop - do not drop current dissect
function hostfakesplit(ctx, desync)
if not desync.dis.tcp then
instance_cutoff(ctx)
instance_cutoff_shim(ctx, desync)
return
end
direction_cutoff_opposite(ctx, desync)
@@ -604,7 +604,7 @@ end
-- arg : nodrop - do not drop current dissect
function fakedsplit(ctx, desync)
if not desync.dis.tcp then
instance_cutoff(ctx)
instance_cutoff_shim(ctx, desync)
return
end
direction_cutoff_opposite(ctx, desync)
@@ -697,7 +697,7 @@ end
-- arg : nodrop - do not drop current dissect
function fakeddisorder(ctx, desync)
if not desync.dis.tcp then
instance_cutoff(ctx)
instance_cutoff_shim(ctx, desync)
return
end
direction_cutoff_opposite(ctx, desync)
@@ -797,7 +797,7 @@ end
-- arg : blob=<blob> - use this data instead of desync.dis.payload
function tcpseg(ctx, desync)
if not desync.dis.tcp then
instance_cutoff(ctx)
instance_cutoff_shim(ctx, desync)
return
end
direction_cutoff_opposite(ctx, desync)
@@ -841,7 +841,7 @@ end
-- arg : pattern_offset=N . offset in the pattern. 0 by default
function udplen(ctx, desync)
if not desync.dis.udp then
instance_cutoff(ctx)
instance_cutoff_shim(ctx, desync)
return
end
direction_cutoff_opposite(ctx, desync)
@@ -877,7 +877,7 @@ end
-- arg : dn=N - message starts from "dN". 2 by default
function dht_dn(ctx, desync)
if not desync.dis.udp then
instance_cutoff(ctx)
instance_cutoff_shim(ctx, desync)
return
end
direction_cutoff_opposite(ctx, desync)

216
lua/zapret-auto.lua Normal file
View File

@@ -0,0 +1,216 @@
function automate_host_record(desync)
if not autostate then
autostate = {}
end
local key = host_or_ip(desync)
if not autostate[key] then
autostate[key] = {}
end
return autostate[key]
end
function automate_conn_record(desync)
if not desync.track.lua_state.automate then
desync.track.lua_state.automate = {}
end
return desync.track.lua_state.automate
end
-- counts failure, optionally (if crec is given) prevents dup failure counts in a single connection
-- if 'maxtime' between failures is exceeded then failure count is reset
-- return true if threshold ('fails') is reached
-- hres is host record. host or ip bound table
-- cres is connection record. connection bound table
function automate_failure_counter(hrec, crec, fails, maxtime)
if crec and crec.failure then
DLOG("automate: duplicate failure in the same connection. not counted")
else
if crec then crec.failure = true end
local tnow=os.time()
if not hrec.failure_time_last then
hrec.failure_time_last = tnow
end
if not hrec.failure_counter then
hrec.failure_counter = 0
elseif tnow>(hrec.failure_time_last + maxtime) then
DLOG("automate: failure counter reset because last failure was "..(tnow - hrec.failure_time_last).." seconds ago")
hrec.failure_counter = 0
end
hrec.failure_counter = hrec.failure_counter + 1
hrec.failure_time_last = tnow
if b_debug then DLOG("automate: failure counter "..hrec.failure_counter..(fails and ('/'..fails) or '')) end
if fails and hrec.failure_counter>=fails then
hrec.failure_counter = nil -- reset counter
return true
end
end
return false
end
-- location is url compatible with Location: header
-- hostname is original hostname
function is_dpi_redirect(hostname, location)
local ds = dissect_url(location)
if ds.domain then
local sld1 = dissect_nld(hostname,2)
local sld2 = dissect_nld(ds.domain,2)
return sld2 and sld1~=sld2
end
return false
end
-- circularily change strategy numbers when failure count reaches threshold ('fails')
-- detected failures: incoming RST, incoming http redirection, outgoing retransmissions
-- this orchestrator requires redirection of incoming traffic to cache RST and http replies !
-- each orchestrated instance must have strategy=N arg, where N starts from 1 and increment without gaps
-- if 'final' arg is present in an orchestrated instance it stops rotation
-- arg: fails=N - failture count threshold. default is 3
-- arg: retrans=N - retrans count threshold. default is 3
-- arg: seq=<rseq> - if packet is beyond this relative sequence number treat this connection as successful. default is 64K
-- arg: rst=<rseq> - maximum relative sequence number to treat incoming RST as DPI reset. default is 1
-- arg: time=<sec> - if last failure happened earlier than `maxtime` seconds ago - reset failure counter. default is 60.
-- test case: nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-auto.lua --in-range=-s1 --lua-desync=circular --lua-desync=argdebug:strategy=1 --lua-desync=argdebug:strategy=2
function circular(ctx, desync)
local function count_strategies(hrec, plan)
if not hrec.ctstrategy then
local uniq={}
local n=0
for i,instance in pairs(plan) do
if instance.arg.strategy then
n = tonumber(instance.arg.strategy)
if not n or n<1 then
error("circular: strategy number '"..tostring(instance.arg.strategy).."' is invalid")
end
uniq[tonumber(instance.arg.strategy)] = true
if instance.arg.final then
hrec.final = n
end
end
end
n=0
for i,v in pairs(uniq) do
n=n+1
end
if n~=#uniq then
error("circular: strategies numbers must start from 1 and increment. gaps are not allowed.")
end
hrec.ctstrategy = n
end
end
-- take over orchestration. prevent further instance execution in case of error
execution_plan_cancel(ctx)
if not desync.dis.tcp then
DLOG("circular: this orchestrator is tcp only")
instance_cutoff(ctx)
return
end
if not desync.track then
DLOG_ERR("circular: conntrack is missing but required")
return
end
local rstseq = tonumber(desync.arg.rst) or 1
local maxseq = tonumber(desync.arg.seq) or 0x10000
local fails = tonumber(desync.arg.fails) or 3
local retrans = tonumber(desync.arg.retrans) or 3
local maxtime = tonumber(desync.arg.time) or 60
local hrec = automate_host_record(desync)
local crec = automate_conn_record(desync)
local pos = bitand(desync.track.tcp.seq - desync.track.tcp.seq0,0xFFFFFFFF)
local trigger = false
local once = true
local plan = execution_plan(ctx)
if #plan==0 then
DLOG("circular: need some desync instances or useless")
return
end
count_strategies(hrec, plan)
if hrec.ctstrategy==0 then
error("circular: add strategy=N tag argument to each following instance ! N must start from 1 and increment")
end
if not hrec.nstrategy then
DLOG("circular: start from strategy 1")
hrec.nstrategy = 1
end
if not crec.nocheck then
local seq = pos_get(desync,'s')
if seq>maxseq then
DLOG("circular: s"..seq.." is beyond s"..maxseq..". treating connection as successful")
crec.nocheck = true
end
end
local verdict = VERDICT_PASS
if not crec.nocheck and hrec.final~=hrec.nstrategy then
if desync.outgoing then
if #desync.dis.payload>0 and (crec.retrans or 0)<retrans then
if not crec.uppos then crec.uppos=0 end
if desync.track.tcp.pos_orig<=crec.uppos then
crec.retrans = crec.retrans and (crec.retrans+1) or 1
DLOG("circular: retransmission "..crec.retrans.."/"..retrans)
trigger = crec.retrans>=retrans
end
if desync.track.tcp.pos_orig>crec.uppos then
crec.uppos=desync.track.tcp.pos_orig
end
end
else
if bitand(desync.dis.tcp.th_flags, TH_RST)~=0 then
local seq=u32add(desync.track.tcp.ack, -desync.track.tcp.ack0)
trigger = seq<=rstseq
if b_debug then
if trigger then
DLOG("circular: incoming RST s"..seq.." in range s"..rstseq)
else
DLOG("circular: not counting incoming RST s"..seq.." beyond s"..rstseq)
end
end
elseif desync.l7payload=="http_reply" and desync.track.hostname then
local hdis = http_dissect_reply(desync.dis.payload)
if hdis and (hdis.code==302 or hdis.code==307) and hdis.headers.location and hdis.headers.location then
trigger = is_dpi_redirect(desync.track.hostname, hdis.headers.location.value)
if trigger and b_debug then
DLOG("circular: http redirect "..hdis.code.." to '"..hdis.headers.location.value.."'")
end
end
end
end
if trigger then
if automate_failure_counter(hrec, crec, fails, maxtime) then
-- circular strategy change
hrec.nstrategy = (hrec.nstrategy % hrec.ctstrategy) + 1
DLOG("circular: rotate strategy to "..hrec.nstrategy)
if hrec.nstrategy == hrec.final then
DLOG("circular: final strategy "..hrec.final.." reached. will rotate no more.")
end
end
end
end
DLOG("circular: current strategy "..hrec.nstrategy)
local dcopy = desync_copy(desync)
for i=1,#plan do
if plan[i].arg.strategy and tonumber(plan[i].arg.strategy)==hrec.nstrategy then
apply_execution_plan(dcopy, plan[i])
if cutoff_shim_check(dcopy) then
DLOG("circular: not calling '"..dcopy.func_instance.."' because of voluntary cutoff")
elseif not payload_match_filter(dcopy.l7payload, plan[i].payload_filter) then
DLOG("circular: not calling '"..dcopy.func_instance.."' because payload '"..dcopy.l7payload.."' does not match filter '"..plan[i].payload_filter.."'")
elseif not pos_check_range(dcopy, plan[i].range) then
DLOG("circular: not calling '"..dcopy.func_instance.."' because pos "..pos_str(dcopy,plan[i].range.from).." "..pos_str(dcopy,plan[i].range.to).." is out of range '"..pos_range_str(plan[i].range).."'")
else
DLOG("circular: executing '"..dcopy.func_instance.."'")
verdict = verdict_aggregate(verdict,_G[plan[i].func](nil, dcopy))
end
end
end
return verdict
end

View File

@@ -61,6 +61,46 @@ function posdebug(ctx,desync)
DLOG(s)
end
-- this shim is needed then function is orchestrated. ctx services not available
-- have to emulate cutoff in LUA using connection persistent table track.lua_state
function instance_cutoff_shim(ctx, desync, dir)
if ctx then
instance_cutoff(ctx, dir)
elseif not desync.track then
DLOG("instance_cutoff_shim: cannot cutoff '"..desync.func_instance.."' because conntrack is absent")
else
if not desync.track.lua_state.cutoff_shim then
desync.track.lua_state.cutoff_shim = {}
end
if not desync.track.lua_state.cutoff_shim[desync.func_instance] then
desync.track.lua_state.cutoff_shim[desync.func_instance] = {}
end
if type(dir)=="nil" then
-- cutoff both directions by default
desync.track.lua_state.cutoff_shim[desync.func_instance][true] = true
desync.track.lua_state.cutoff_shim[desync.func_instance][false] = true
else
desync.track.lua_state.cutoff_shim[desync.func_instance][dir] = true
end
if b_debug then DLOG("instance_cutoff_shim: cutoff '"..desync.func_instance.."' in="..tostring(type(dir)=="nil" and true or not dir).." out="..tostring(type(dir)=="nil" or dir)) end
end
end
function cutoff_shim_check(desync)
if not desync.track then
DLOG("cutoff_shim_check: cannot check '"..desync.func_instance.."' cutoff because conntrack is absent")
return false
else
local b=desync.track.lua_state.cutoff_shim and
desync.track.lua_state.cutoff_shim[desync.func_instance] and
desync.track.lua_state.cutoff_shim[desync.func_instance][desync.outgoing]
if b and b_debug then
DLOG("cutoff_shim_check: '"..desync.func_instance.."' "..(desync.outgoing and "out" or "in").." cutoff")
end
return b
end
end
-- applies # and $ prefixes. #var means var length, %var means var value
function apply_arg_prefix(arg)
for a,v in pairs(arg) do
@@ -100,21 +140,34 @@ function verdict_aggregate(v1, v2)
return v
end
-- redo what whould be done without orchestration
function replay_execution_plan(ctx, desync, plan)
function replay_execution_plan(desync, plan)
local verdict = VERDICT_PASS
for i=1,#plan do
if not payload_match_filter(desync.l7payload, plan[i].payload_filter) then
if cutoff_shim_check(desync) then
DLOG("orchestrator: not calling '"..desync.func_instance.."' because of voluntary cutoff")
elseif not payload_match_filter(desync.l7payload, plan[i].payload_filter) then
DLOG("orchestrator: not calling '"..desync.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.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, plan[i])
DLOG("orchestrator: executing '"..desync.func_instance.."'")
verdict = verdict_aggregate(verdict,_G[plan[i].func](ctx, desync))
verdict = verdict_aggregate(verdict,_G[plan[i].func](nil, desync))
end
end
return verdict
end
-- copy desync preserving lua_state
function desync_copy(desync)
local dcopy = deepcopy(desync)
if desync.track then
-- preserve lua state
dcopy.track.lua_state = desync.track.lua_state
end
return dcopy
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
@@ -122,9 +175,9 @@ 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)
local dcopy = desync_copy(desync)
execution_plan_cancel(ctx)
return replay_execution_plan(ctx, desync_copy, plan)
return replay_execution_plan(dcopy, plan)
end
end
@@ -257,7 +310,7 @@ function var_debug(v)
local function dbg(v,level)
if type(v)=="table" then
for key, value in pairs(v) do
DLOG(string.rep(" ",2*level).."."..key)
DLOG(string.rep(" ",2*level).."."..tostring(key))
dbg(v[key],level+1)
end
elseif type(v)=="string" then
@@ -1010,10 +1063,10 @@ function direction_cutoff_opposite(ctx, desync, def)
local dir = desync.arg.dir or def or "out"
if dir=="out" then
-- cutoff in
instance_cutoff(ctx, false)
instance_cutoff_shim(ctx, desync, false)
elseif dir=="in" then
-- cutoff out
instance_cutoff(ctx, true)
instance_cutoff_shim(ctx, desync, true)
end
end
@@ -1103,7 +1156,10 @@ end
-- return hostname if present or ip address in text form otherwise
function host_or_ip(desync)
return desync.hostname or (desync.dis.ip and ntop(desync.dis.ip) or desync.dis.ip6 and ntop(desync.dis.ip6))
if desync.track and desync.track.hostname then
return desync.track.hostname
end
return desync.target.ip and ntop(desync.target.ip) or desync.target.ip6 and ntop(desync.target.ip6)
end
function is_absolute_path(path)
@@ -1254,3 +1310,16 @@ function ipfrag2(dis, ipfrag_options)
return {dis1,dis2}
end
-- location is url compatible with Location: header
-- hostname is original hostname
function is_dpi_redirect(hostname, location)
local ds = dissect_url(location)
if ds.domain then
local sld1 = dissect_nld(hostname,2)
local sld2 = dissect_nld(ds.domain,2)
return sld2 and sld1~=sld2
end
return false
end

View File

@@ -648,6 +648,7 @@ static uint8_t desync(
const t_ctrack_position *pos,
t_l7payload l7payload,
const struct dissect *dis,
const struct in_addr *sdp4, const struct in6_addr *sdp6, uint16_t sdport,
uint8_t *mod_pkt, size_t *len_mod_pkt,
unsigned int replay_piece, unsigned int replay_piece_count, size_t reasm_offset, const uint8_t *rdata_payload, size_t rlen_payload,
const uint8_t *data_decrypt, size_t len_decrypt)
@@ -677,6 +678,9 @@ static uint8_t desync(
}
if (!pos) pos = &ctrack->pos;
}
LUA_STACK_GUARD_ENTER(params.L)
if (LIST_FIRST(&dp->lua_desync))
{
b_cutoff_all = b_unwanted_payload = true;
@@ -733,6 +737,12 @@ static uint8_t desync(
lua_pushf_str("ifin", (ifin && *ifin) ? ifin : NULL);
lua_pushf_str("ifout", (ifout && *ifout) ? ifout : NULL);
lua_pushf_int("fwmark", fwmark);
lua_pushf_table("target");
lua_getfield(params.L,-1,"target");
if (sdport) lua_pushf_int("port",sdport);
if (sdp4) lua_pushf_lstr("ip",(const char*)sdp4,sizeof(*sdp4));
if (sdp6) lua_pushf_lstr("ip6",(const char*)sdp6,sizeof(*sdp6));
lua_pop(params.L,1);
lua_pushf_bool("replay", !!replay_piece_count);
if (replay_piece_count)
{
@@ -864,6 +874,7 @@ static uint8_t desync(
DLOG("no lua functions in this profile\n");
ex:
luaL_unref(params.L, LUA_REGISTRYINDEX, ref_arg);
LUA_STACK_GUARD_LEAVE(params.L, 0)
return verdict;
err:
DLOG_ERR("desync ERROR. passing packet unmodified.\n");
@@ -1354,7 +1365,7 @@ static uint8_t dpi_desync_tcp_packet_play(
ntop46_port((struct sockaddr *)&dst, s2, sizeof(s2));
DLOG("dpi desync src=%s dst=%s track_direction=%s fixed_direction=%s connection_proto=%s payload_type=%s\n", s1, s2, bReverse ? "in" : "out", bReverseFixed ? "in" : "out", l7proto_str(l7proto), l7payload_str(l7payload));
}
verdict = desync(dp, fwmark, ifin, ifout, bReverseFixed, ctrack_replay, pos, l7payload, dis, mod_pkt, len_mod_pkt, replay_piece, replay_piece_count, reasm_offset, rdata_payload, rlen_payload, NULL, 0);
verdict = desync(dp, fwmark, ifin, ifout, bReverseFixed, ctrack_replay, pos, l7payload, dis, sdip4, sdip6, sdport, mod_pkt, len_mod_pkt, replay_piece, replay_piece_count, reasm_offset, rdata_payload, rlen_payload, NULL, 0);
pass:
return (!bReverseFixed && (verdict & VERDICT_MASK) == VERDICT_DROP) ? ct_new_postnat_fix(ctrack, dis, mod_pkt, len_mod_pkt) : verdict;
@@ -1810,7 +1821,7 @@ static uint8_t dpi_desync_udp_packet_play(
ntop46_port((struct sockaddr *)&dst, s2, sizeof(s2));
DLOG("dpi desync src=%s dst=%s track_direction=%s fixed_direction=%s connection_proto=%s payload_type=%s\n", s1, s2, bReverse ? "in" : "out", bReverseFixed ? "in" : "out", l7proto_str(l7proto), l7payload_str(l7payload));
}
verdict = desync(dp, fwmark, ifin, ifout, bReverseFixed, ctrack_replay, pos, l7payload, dis, mod_pkt, len_mod_pkt, replay_piece, replay_piece_count, reasm_offset, NULL, 0, data_decrypt, len_decrypt);
verdict = desync(dp, fwmark, ifin, ifout, bReverseFixed, ctrack_replay, pos, l7payload, dis, sdip4, sdip6, sdport, mod_pkt, len_mod_pkt, replay_piece, replay_piece_count, reasm_offset, NULL, 0, data_decrypt, len_decrypt);
pass:
return (!bReverse && (verdict & VERDICT_MASK) == VERDICT_DROP) ? ct_new_postnat_fix(ctrack, dis, mod_pkt, len_mod_pkt) : verdict;

View File

@@ -692,8 +692,8 @@ static int luacall_clock_gettime(lua_State *L)
}
static int luacall_instance_cutoff(lua_State *L)
{
// out : func_name.profile_number[0]
// in : func_name.profile_number[1]
// out : instance_name.profile_number[0]
// in : instance_name.profile_number[1]
lua_check_argc_range(L,"instance_cutoff",1,2);
@@ -701,45 +701,51 @@ static int luacall_instance_cutoff(lua_State *L)
const t_lua_desync_context *ctx;
if (!lua_islightuserdata(L,1))
luaL_error(L, "instance_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;
}
if (lua_isnil(L,1))
// this can happen in orchestrated function. they do not have their own ctx and they cant cutoff
DLOG("instance cutoff not possible because missing ctx\n");
else
bIn = bOut = true;
if (ctx->ctrack)
{
DLOG("instance cutoff for '%s' in=%u out=%u\n",ctx->instance,bIn,bOut);
lua_rawgeti(L,LUA_REGISTRYINDEX,ctx->ctrack->lua_instance_cutoff);
lua_getfield(L,-1,ctx->instance);
if (!lua_istable(L,-1))
if (!lua_islightuserdata(L,1))
luaL_error(L, "instance_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)
{
lua_pop(L,1);
lua_pushf_table(ctx->instance);
luaL_checktype(L,2,LUA_TBOOLEAN);
bOut = lua_toboolean(L,2);
bIn = !bOut;
}
else
bIn = bOut = true;
if (ctx->ctrack)
{
DLOG("instance cutoff for '%s' in=%u out=%u\n",ctx->instance,bIn,bOut);
lua_rawgeti(L,LUA_REGISTRYINDEX,ctx->ctrack->lua_instance_cutoff);
lua_getfield(L,-1,ctx->instance);
}
lua_rawgeti(L,-1,ctx->dp->n);
if (!lua_istable(L,-1))
{
lua_pop(L,1);
lua_pushi_table(ctx->dp->n);
if (!lua_istable(L,-1))
{
lua_pop(L,1);
lua_pushf_table(ctx->instance);
lua_getfield(L,-1,ctx->instance);
}
lua_rawgeti(L,-1,ctx->dp->n);
if (!lua_istable(L,-1))
{
lua_pop(L,1);
lua_pushi_table(ctx->dp->n);
lua_rawgeti(L,-1,ctx->dp->n);
}
if (bOut) lua_pushi_bool(0,true);
if (bIn) lua_pushi_bool(1,true);
lua_pop(L,3);
}
if (bOut) lua_pushi_bool(0,true);
if (bIn) lua_pushi_bool(1,true);
lua_pop(L,3);
else
DLOG("instance cutoff requested for '%s' in=%u out=%u but not possible without conntrack\n",ctx->instance,bIn,bOut);
}
else
DLOG("instance cutoff requested for '%s' in=%u out=%u but not possible without conntrack\n",ctx->instance,bIn,bOut);
LUA_STACK_GUARD_RETURN(L,0)
}
@@ -935,6 +941,18 @@ void lua_pushi_str(lua_Integer idx, const char *str)
lua_pushstring(params.L, str); // pushes nil if str==NULL
lua_rawset(params.L,-3);
}
void lua_pushf_lstr(const char *field, const char *str, size_t size)
{
lua_pushstring(params.L, field);
lua_pushlstring(params.L, str, size);
lua_rawset(params.L,-3);
}
void lua_pushi_lstr(lua_Integer idx, const char *str, size_t size)
{
lua_pushinteger(params.L, idx);
lua_pushlstring(params.L, str, size);
lua_rawset(params.L,-3);
}
void lua_push_raw(const void *v, size_t l)
{
if (v)

View File

@@ -51,6 +51,8 @@ void lua_pushf_bool(const char *field, bool b);
void lua_pushi_bool(lua_Integer idx, bool b);
void lua_pushf_str(const char *field, const char *str);
void lua_pushi_str(lua_Integer idx, const char *str);
void lua_pushf_lstr(const char *field, const char *str, size_t len);
void lua_pushi_lstr(lua_Integer idx, const char *str, size_t len);
void lua_pushf_int(const char *field, lua_Integer v);
void lua_pushi_int(lua_Integer idx, lua_Integer v);
void lua_push_raw(const void *v, size_t l);