diff --git a/lua/zapret-auto.lua b/lua/zapret-auto.lua index 0ef9380..f7e895c 100644 --- a/lua/zapret-auto.lua +++ b/lua/zapret-auto.lua @@ -72,42 +72,53 @@ end -- standard failure detector -- works with tcp and udp -- detected failures: --- incoming RST (within `options.seq_rst`) --- incoming http redirection (if no 'options.no_http_redirect') --- outgoing retransmissions (`options.retrans` threshold) --- udp : >= `options.udp_out` outgoings with <= 'options.udp_in' incomings --- stops dectecting after seq 'options.maxseq' -function standard_failure_detector(desync, crec, options) +-- incoming RST +-- incoming http redirection +-- outgoing retransmissions +-- udp too much out with too few in +-- arg: seq= - tcp: if packet is beyond this relative sequence number treat this connection as successful. default is 64K +-- arg: retrans=N - tcp: retrans count threshold. default is 3 +-- arg: rst= - tcp: maximum relative sequence number to treat incoming RST as DPI reset. default is 1 +-- arg: no_http_redirect - tcp: disable http_reply dpi redirect trigger +-- arg: udp_out - udp: >= outgoing udp packets. default is 3 +-- arg: udp_in - udp: with <= incoming udp packets. default is 1 +function standard_failure_detector(desync, crec, arg) if crec.nocheck then return false end + local seq_rst = tonumber(arg.rst) or 1 + local retrans = tonumber(arg.retrans) or 3 + local maxseq = tonumber(arg.seq) or 0x10000 + local udp_in = tonumber(arg.udp_in) or 1 + local udp_out = tonumber(arg.udp_out) or 3 + local trigger = false if desync.dis.tcp then 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") + if maxseq and seq>maxseq then + DLOG("standard_failure_detector: s"..seq.." is beyond s"..maxseq..". treating connection as successful") crec.nocheck = true return false end if desync.outgoing then - if #desync.dis.payload>0 and options.retrans and (crec.retrans or 0)0 and retrans and (crec.retrans or 0)=options.retrans + DLOG("standard_failure_detector: retransmission "..crec.retrans.."/"..retrans) + trigger = crec.retrans>=retrans end end else - if options.seq_rst and bitand(desync.dis.tcp.th_flags, TH_RST)~=0 then - trigger = seq<=options.seq_rst + if seq_rst and bitand(desync.dis.tcp.th_flags, TH_RST)~=0 then + trigger = seq<=seq_rst if b_debug then if trigger then - DLOG("standard_failure_detector: incoming RST s"..seq.." in range s"..options.seq_rst) + DLOG("standard_failure_detector: incoming RST s"..seq.." in range s"..seq_rst) else - DLOG("standard_failure_detector: not counting incoming RST s"..seq.." beyond s"..options.seq_rst) + DLOG("standard_failure_detector: not counting incoming RST s"..seq.." beyond s"..seq_rst) end end - elseif not options.no_http_redirect and desync.l7payload=="http_reply" and desync.track.hostname then + elseif not arg.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) @@ -123,13 +134,13 @@ function standard_failure_detector(desync, crec, options) end elseif desync.dis.udp then if desync.outgoing then - if options.udp_out then - local udp_in = options.udp_in or 0 - trigger = desync.track.pcounter_orig>=options.udp_out and desync.track.pcounter_reply<=udp_in + if udp_out then + local udp_in = udp_in or 0 + trigger = desync.track.pcounter_orig>=udp_out and desync.track.pcounter_reply<=udp_in if trigger then crec.nocheck = true if b_debug then - DLOG("standard_failure_detector: udp_out "..desync.track.pcounter_orig..">="..options.udp_out.." udp_in "..desync.track.pcounter_reply.."<="..udp_in) + DLOG("standard_failure_detector: udp_out "..desync.track.pcounter_orig..">="..udp_out.." udp_in "..desync.track.pcounter_reply.."<="..udp_in) end end end @@ -137,16 +148,6 @@ function standard_failure_detector(desync, crec, options) end return trigger end --- prepare options table from args -function standard_failure_detector_options(arg) - return { - seq_rst = tonumber(arg.rst) or 1, - retrans = tonumber(arg.retrans) or 3, - maxseq = tonumber(arg.seq) or 0x10000, - udp_in = tonumber(arg.udp_in) or 1, - udp_out = tonumber(arg.udp_out) or 3 - } -end -- circularily change strategy numbers when failure count reaches threshold ('fails') -- works with tcp only @@ -154,14 +155,9 @@ end -- 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= - if packet is beyond this relative sequence number treat this connection as successful. default is 64K --- arg: rst= - maximum relative sequence number to treat incoming RST as DPI reset. default is 1 -- arg: time= - 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: udp_out - >= outgoing udp packets. default is 3 --- arg: udp_in - with <= incoming udp packets. default is 1 --- arg: detector - failure detector function name. '_options' function converts parameters from arg to options table. +-- 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 function circular(ctx, desync) local function count_strategies(hrec, plan) @@ -226,20 +222,19 @@ function circular(ctx, desync) local crec = automate_conn_record(desync) local fails = tonumber(desync.arg.fails) or 3 local maxtime = tonumber(desync.arg.time) or 60 - local failure_detector, failure_detector_getopts + local failure_detector 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] - failure_detector_getopts = _G[desync.arg.detector.."_options"] or standard_failure_detector_options else failure_detector = standard_failure_detector - failure_detector_getopts = standard_failure_detector_options end - if failure_detector(desync,crec,failure_detector_getopts(desync.arg)) then + if failure_detector(desync,crec,desync.arg) then + -- failure happened. count failures. if automate_failure_counter(hrec, crec, fails, maxtime) then - -- circular strategy change + -- counter reaches threshold. circular strategy change hrec.nstrategy = (hrec.nstrategy % hrec.ctstrategy) + 1 DLOG("circular: rotate strategy to "..hrec.nstrategy) if hrec.nstrategy == hrec.final then