mirror of
https://github.com/bol-van/zapret2.git
synced 2026-03-22 17:25:47 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c35e8949a | ||
|
|
7edd428508 | ||
|
|
7749fce7dc | ||
|
|
ea6e1e0853 | ||
|
|
7d2f12cbad |
@@ -26,7 +26,7 @@ CURL=${CURL:-curl}
|
|||||||
|
|
||||||
TEST_DEFAULT=${TEST_DEFAULT:-standard}
|
TEST_DEFAULT=${TEST_DEFAULT:-standard}
|
||||||
DOMAINS_DEFAULT=${DOMAINS_DEFAULT:-rutracker.org}
|
DOMAINS_DEFAULT=${DOMAINS_DEFAULT:-rutracker.org}
|
||||||
QNUM=${QNUM:-59780}
|
QNUM=${QNUM:-59781}
|
||||||
SOCKS_PORT=${SOCKS_PORT:-1993}
|
SOCKS_PORT=${SOCKS_PORT:-1993}
|
||||||
WS_UID=${WS_UID:-1}
|
WS_UID=${WS_UID:-1}
|
||||||
WS_GID=${WS_GID:-3003}
|
WS_GID=${WS_GID:-3003}
|
||||||
@@ -1354,7 +1354,7 @@ check_domain_http_udp()
|
|||||||
[ "$SKIP_PKTWS" = 1 ] || {
|
[ "$SKIP_PKTWS" = 1 ] || {
|
||||||
echo
|
echo
|
||||||
echo preparing $PKTWSD redirection
|
echo preparing $PKTWSD redirection
|
||||||
mdig_resolve_all $IPV ips $4
|
mdig_resolve_all $IPV ips $3
|
||||||
pktws_ipt_prepare_udp $2 "$ips"
|
pktws_ipt_prepare_udp $2 "$ips"
|
||||||
|
|
||||||
pktws_check_domain_http3_bypass $1 $3
|
pktws_check_domain_http3_bypass $1 $3
|
||||||
|
|||||||
@@ -61,3 +61,8 @@ v0.5
|
|||||||
* zapret-lib: http_reply, url and nld dissectors
|
* zapret-lib: http_reply, url and nld dissectors
|
||||||
* zapret-lib: instance_cutoff_shim
|
* zapret-lib: instance_cutoff_shim
|
||||||
* zapret-auto: circular orchestrator
|
* zapret-auto: circular orchestrator
|
||||||
|
|
||||||
|
v0.5.1
|
||||||
|
|
||||||
|
* zapret-auto: separate failure detection logic
|
||||||
|
* blockcheck2: fix broken http3 test
|
||||||
|
|||||||
@@ -69,8 +69,65 @@ function is_dpi_redirect(hostname, location)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- standard failure detector
|
||||||
|
-- works with tcp only
|
||||||
|
-- detected failures:
|
||||||
|
-- incoming RST (within `options.seq_rst`)
|
||||||
|
-- incoming http redirection (if no 'options.no_http_redirect')
|
||||||
|
-- outgoing retransmissions (`options.retrans` threshold)
|
||||||
|
-- stops dectecting after seq 'options.maxseq'
|
||||||
|
function standard_failure_detector(desync, crec, options)
|
||||||
|
if not desync.dis.tcp or crec.nocheck then return false end
|
||||||
|
local seq = pos_get(desync,'s')
|
||||||
|
if options.maxseq and seq>options.maxseq then
|
||||||
|
DLOG("standard_failure_detector: s"..seq.." is beyond s"..options.maxseq..". treating connection as successful")
|
||||||
|
crec.nocheck = true
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local trigger = false
|
||||||
|
local seq = pos_get(desync,'s')
|
||||||
|
if desync.outgoing then
|
||||||
|
if #desync.dis.payload>0 and options.retrans and (crec.retrans or 0)<options.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("standard_failure_detector: retransmission "..crec.retrans.."/"..options.retrans)
|
||||||
|
trigger = crec.retrans>=options.retrans
|
||||||
|
end
|
||||||
|
if desync.track.tcp.pos_orig>crec.uppos then
|
||||||
|
crec.uppos=desync.track.tcp.pos_orig
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if options.seq_rst and bitand(desync.dis.tcp.th_flags, TH_RST)~=0 then
|
||||||
|
trigger = seq<=options.seq_rst
|
||||||
|
if b_debug then
|
||||||
|
if trigger then
|
||||||
|
DLOG("standard_failure_detector: incoming RST s"..seq.." in range s"..options.seq_rst)
|
||||||
|
else
|
||||||
|
DLOG("standard_failure_detector: not counting incoming RST s"..seq.." beyond s"..options.seq_rst)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif not options.no_http_redirect and 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 b_debug then
|
||||||
|
if trigger then
|
||||||
|
DLOG("standard_failure_detector: http redirect "..hdis.code.." to '"..hdis.headers.location.value.."'. looks like DPI redirect.")
|
||||||
|
else
|
||||||
|
DLOG("standard_failure_detector: http redirect "..hdis.code.." to '"..hdis.headers.location.value.."'. NOT a DPI redirect.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return trigger
|
||||||
|
end
|
||||||
|
|
||||||
-- circularily change strategy numbers when failure count reaches threshold ('fails')
|
-- circularily change strategy numbers when failure count reaches threshold ('fails')
|
||||||
-- detected failures: incoming RST, incoming http redirection, outgoing retransmissions
|
-- works with tcp only
|
||||||
-- this orchestrator requires redirection of incoming traffic to cache RST and http replies !
|
-- 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
|
-- 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
|
-- if 'final' arg is present in an orchestrated instance it stops rotation
|
||||||
@@ -80,6 +137,7 @@ end
|
|||||||
-- arg: rst=<rseq> - maximum relative sequence number to treat incoming RST as DPI reset. default is 1
|
-- 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.
|
-- arg: time=<sec> - if last failure happened earlier than `maxtime` seconds ago - reset failure counter. default is 60.
|
||||||
-- arg: reqhost - pass with no tampering if hostname is unavailable
|
-- arg: reqhost - pass with no tampering if hostname is unavailable
|
||||||
|
-- arg: detector - failure detector function name
|
||||||
-- 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
|
-- 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)
|
function circular(ctx, desync)
|
||||||
local function count_strategies(hrec, plan)
|
local function count_strategies(hrec, plan)
|
||||||
@@ -113,7 +171,7 @@ function circular(ctx, desync)
|
|||||||
execution_plan_cancel(ctx)
|
execution_plan_cancel(ctx)
|
||||||
|
|
||||||
if not desync.dis.tcp then
|
if not desync.dis.tcp then
|
||||||
DLOG("circular: this orchestrator is tcp only")
|
DLOG_ERR("circular: this orchestrator is tcp only. use filters to avoid udp traffic.")
|
||||||
instance_cutoff(ctx)
|
instance_cutoff(ctx)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -139,64 +197,30 @@ function circular(ctx, desync)
|
|||||||
error("circular: add strategy=N tag argument to each following instance ! N must start from 1 and increment")
|
error("circular: add strategy=N tag argument to each following instance ! N must start from 1 and increment")
|
||||||
end
|
end
|
||||||
|
|
||||||
local rstseq = tonumber(desync.arg.rst) or 1
|
local seq_rst = tonumber(desync.arg.rst) or 1
|
||||||
local maxseq = tonumber(desync.arg.seq) or 0x10000
|
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 retrans = tonumber(desync.arg.retrans) or 3
|
||||||
|
local fails = tonumber(desync.arg.fails) or 3
|
||||||
local maxtime = tonumber(desync.arg.time) or 60
|
local maxtime = tonumber(desync.arg.time) or 60
|
||||||
local crec = automate_conn_record(desync)
|
local crec = automate_conn_record(desync)
|
||||||
local pos = bitand(desync.track.tcp.seq - desync.track.tcp.seq0,0xFFFFFFFF)
|
local failure_detector
|
||||||
local trigger = false
|
if desync.arg.detector then
|
||||||
|
if type(_G[desync.arg.detector])~="function" then
|
||||||
|
error("circular: invalid failure detector function '"..desync.arg.detector.."'")
|
||||||
|
end
|
||||||
|
failure_detector = _G[desync.arg.detector]
|
||||||
|
else
|
||||||
|
failure_detector = standard_failure_detector
|
||||||
|
end
|
||||||
|
|
||||||
if not hrec.nstrategy then
|
if not hrec.nstrategy then
|
||||||
DLOG("circular: start from strategy 1")
|
DLOG("circular: start from strategy 1")
|
||||||
hrec.nstrategy = 1
|
hrec.nstrategy = 1
|
||||||
end
|
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
|
local verdict = VERDICT_PASS
|
||||||
if not crec.nocheck and hrec.final~=hrec.nstrategy then
|
if hrec.final~=hrec.nstrategy then
|
||||||
if desync.outgoing then
|
if failure_detector(desync,crec,{retrans=retrans,maxseq=maxseq,seq_rst=seq_rst}) 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
|
if automate_failure_counter(hrec, crec, fails, maxtime) then
|
||||||
-- circular strategy change
|
-- circular strategy change
|
||||||
hrec.nstrategy = (hrec.nstrategy % hrec.ctstrategy) + 1
|
hrec.nstrategy = (hrec.nstrategy % hrec.ctstrategy) + 1
|
||||||
@@ -212,17 +236,7 @@ function circular(ctx, desync)
|
|||||||
local dcopy = desync_copy(desync)
|
local dcopy = desync_copy(desync)
|
||||||
for i=1,#plan do
|
for i=1,#plan do
|
||||||
if plan[i].arg.strategy and tonumber(plan[i].arg.strategy)==hrec.nstrategy then
|
if plan[i].arg.strategy and tonumber(plan[i].arg.strategy)==hrec.nstrategy then
|
||||||
apply_execution_plan(dcopy, plan[i])
|
verdict = plan_instance_execute(dcopy, verdict, 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: calling '"..dcopy.func_instance.."'")
|
|
||||||
verdict = verdict_aggregate(verdict,_G[plan[i].func](nil, dcopy))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -118,11 +118,11 @@ function apply_arg_prefix(arg)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- copy instance identification and args from execution plan to desync table
|
-- copy instance identification and args from execution plan to desync table
|
||||||
function apply_execution_plan(desync, plan)
|
function apply_execution_plan(desync, instance)
|
||||||
desync.func = plan.func
|
desync.func = instance.func
|
||||||
desync.func_n = plan.func_n
|
desync.func_n = instance.func_n
|
||||||
desync.func_instance = plan.func_instance
|
desync.func_instance = instance.func_instance
|
||||||
desync.arg = deepcopy(plan.arg)
|
desync.arg = deepcopy(instance.arg)
|
||||||
apply_arg_prefix(desync.arg)
|
apply_arg_prefix(desync.arg)
|
||||||
end
|
end
|
||||||
-- produce resulting verdict from 2 verdicts
|
-- produce resulting verdict from 2 verdicts
|
||||||
@@ -139,21 +139,26 @@ function verdict_aggregate(v1, v2)
|
|||||||
end
|
end
|
||||||
return v
|
return v
|
||||||
end
|
end
|
||||||
|
function plan_instance_execute(desync, verdict, instance)
|
||||||
|
apply_execution_plan(desync, instance)
|
||||||
|
if cutoff_shim_check(desync) then
|
||||||
|
DLOG("plan_instance_execute: not calling '"..desync.func_instance.."' because of voluntary cutoff")
|
||||||
|
elseif not payload_match_filter(desync.l7payload, instance.payload_filter) then
|
||||||
|
DLOG("plan_instance_execute: not calling '"..desync.func_instance.."' because payload '"..desync.l7payload.."' does not match filter '"..instance.payload_filter.."'")
|
||||||
|
elseif not pos_check_range(desync, instance.range) then
|
||||||
|
DLOG("plan_instance_execute: not calling '"..desync.func_instance.."' because pos "..pos_str(desync,instance.range.from).." "..pos_str(desync,instance.range.to).." is out of range '"..pos_range_str(instance.range).."'")
|
||||||
|
else
|
||||||
|
DLOG("plan_instance_execute: calling '"..desync.func_instance.."'")
|
||||||
|
verdict = verdict_aggregate(verdict,_G[instance.func](nil, desync))
|
||||||
|
end
|
||||||
|
return verdict
|
||||||
|
end
|
||||||
|
|
||||||
-- redo what whould be done without orchestration
|
-- redo what whould be done without orchestration
|
||||||
function replay_execution_plan(desync, plan)
|
function replay_execution_plan(desync, plan)
|
||||||
local verdict = VERDICT_PASS
|
local verdict = VERDICT_PASS
|
||||||
for i=1,#plan do
|
for i=1,#plan do
|
||||||
if cutoff_shim_check(desync) then
|
verdict = plan_instance_execute(desync, verdict, plan[i])
|
||||||
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: calling '"..desync.func_instance.."'")
|
|
||||||
verdict = verdict_aggregate(verdict,_G[plan[i].func](nil, desync))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
return verdict
|
return verdict
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user