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

zapret-obfs: ippxor

This commit is contained in:
bol-van
2026-01-27 13:25:13 +03:00
parent 68c15864a4
commit 5b016f62e4
6 changed files with 110 additions and 20 deletions

2
.gitattributes vendored
View File

@@ -1,5 +1,7 @@
* text=auto eol=lf * text=auto eol=lf
*.cmd eol=crlf *.cmd eol=crlf
*.bat eol=crlf *.bat eol=crlf
*.manifest eol=crlf
*.rc eol=crlf
init.d/windivert.filter.examples/** eol=crlf init.d/windivert.filter.examples/** eol=crlf
files/** binary files/** binary

View File

@@ -175,6 +175,9 @@ end
-- produce resulting verdict from 2 verdicts -- produce resulting verdict from 2 verdicts
function verdict_aggregate(v1, v2) function verdict_aggregate(v1, v2)
local v local v
local vn = bitor(bitand(v1,VERDICT_PRESERVE_NEXT),bitand(v2,VERDICT_PRESERVE_NEXT))
v1 = bitand(v1, VERDICT_MASK)
v2 = bitand(v2, VERDICT_MASK)
v1 = v1 or VERDICT_PASS v1 = v1 or VERDICT_PASS
v2 = v2 or VERDICT_PASS v2 = v2 or VERDICT_PASS
if v1==VERDICT_DROP or v2==VERDICT_DROP then if v1==VERDICT_DROP or v2==VERDICT_DROP then
@@ -184,7 +187,7 @@ function verdict_aggregate(v1, v2)
else else
v=VERDICT_PASS v=VERDICT_PASS
end end
return v return bitor(v,vn)
end end
function plan_instance_execute(desync, verdict, instance) function plan_instance_execute(desync, verdict, instance)
apply_execution_plan(desync, instance) apply_execution_plan(desync, instance)
@@ -751,6 +754,14 @@ function dis_reverse(dis)
end end
end end
function dis_reconstruct_l3(dis, options)
if dis.ip then
return csum_ip4_fix(reconstruct_iphdr(dis.ip))
elseif dis.ip6 then
return reconstruct_ip6hdr(dis.ip6, options)
end
end
-- parse autottl : delta,min-max -- parse autottl : delta,min-max
function parse_autottl(s) function parse_autottl(s)
if s then if s then

View File

@@ -42,7 +42,7 @@ function wgobfs(ctx, desync)
return return
end end
if not desync.arg.secret or #desync.arg.secret==0 then if not desync.arg.secret or #desync.arg.secret==0 then
error("wgobfs requires secret") error("wgobfs: secret required")
end end
if padmin>padmax then if padmin>padmax then
error("wgobfs: padmin>padmax") error("wgobfs: padmin>padmax")
@@ -78,3 +78,71 @@ function wgobfs(ctx, desync)
end end
end end
end end
-- test case :
-- endpoint1:
-- --filter-icmp=0,8,128,129 --filter-ipp=193,198,209,250 --filter-tcp=* --filter-udp=* --in-range=a --lua-desync=ippxor:xor=192:dataxor=0xABCD
-- nft add rule inet ztest pre meta mark and 0x40000000 == 0 meta l4proto {193, 198, 209, 250} queue num 200 bypass
-- nft add rule inet ztest post meta mark and 0x40000000 == 0 tcp dport "{5001}" queue num 200 bypass
-- nft add rule inet ztest post meta mark and 0x40000000 == 0 udp dport "{5001}" queue num 200 bypass
-- iperf -i 1 -c endpoint2
-- endpoint2:
-- --filter-icmp=0,8,128,129 --filter-ipp=193,198,209,250 --filter-tcp=* --filter-udp=* --in-range=a --lua-desync=ippxor:xor=192:dataxor=0xABCD --server
-- nft add rule inet ztest pre meta mark and 0x40000000 == 0 meta l4proto {193, 198, 209, 250} queue num 200 bypass
-- nft add rule inet ztest post meta mark and 0x40000000 == 0 tcp sport "{5001}" queue num 200 bypass
-- nft add rule inet ztest post meta mark and 0x40000000 == 0 udp sport "{5001}" queue num 200 bypass
-- iperf -s
-- xor ip protocol number and optionally xor tcp,udp,icmp payload with supplied blob pattern
-- arg : ippxor - value to xor ip protocol number
-- arg : dataxor - blob to xor tcp, udp or icmp payload
function ippxor(ctx, desync)
local dataxor
local function dxor(dis)
if dataxor and dis.payload and #dis.payload>0 and (dis.tcp or dis.udp or dis.icmp) then
dis.payload = bxor(dis.payload, pattern(dataxor,1,#dis.payload))
return true
end
return false
end
if not desync.arg.ippxor then
error("ippxor: ippxor value required")
end
local ippxor = tonumber(desync.arg.ippxor)
if ippxor<0 or ippxor>0xFF then
error("ippxor: invalid ippxor value. should be 0..255")
end
if desync.arg.dataxor then
dataxor = blob(desync,desync.arg.dataxor)
if #dataxor==0 then
error("ippxor: empty dataxor value")
end
end
local l3_from = ip_proto_l3(desync.dis)
local l3_to = bitxor(l3_from, ippxor)
local bdxor = dxor(desync.dis)
if bdxor then
DLOG("ippxor: dataxor out")
end
fix_ip_proto(desync.dis, l3_to)
local raw_ip = reconstruct_dissect(desync.dis, {ip6_preserve_next=true})
local dis = dissect(raw_ip)
if not dis.ip and not dis.ip6 then
DLOG_ERR("ippxor: could not rebuild packet")
return
end
if not bdxor then
if dxor(dis) then
DLOG("ippxor: dataxor in")
end
end
desync.dis = dis
DLOG("ippxor: "..l3_from.." => "..l3_to)
return VERDICT_MODIFY + VERDICT_PRESERVE_NEXT
end

View File

@@ -99,8 +99,10 @@ uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment);
#define VERDICT_MODIFY 1 #define VERDICT_MODIFY 1
#define VERDICT_DROP 2 #define VERDICT_DROP 2
#define VERDICT_MASK 3 #define VERDICT_MASK 3
#define VERDICT_NOCSUM 4 #define VERDICT_PRESERVE_NEXT 4
#define VERDICT_MASK_VALID 7 #define VERDICT_MASK_VALID_LUA (VERDICT_MASK|VERDICT_PRESERVE_NEXT)
#define VERDICT_NOCSUM 8
#define VERDICT_MASK_VALID 15
#define IP4_TOS(ip_header) (ip_header ? ip_header->ip_tos : 0) #define IP4_TOS(ip_header) (ip_header ? ip_header->ip_tos : 0)
#define IP4_IP_ID(ip_header) (ip_header ? ip_header->ip_id : 0) #define IP4_IP_ID(ip_header) (ip_header ? ip_header->ip_id : 0)

View File

@@ -227,6 +227,7 @@ static bool dp_match(
if (!port_filters_match(&dp->pf_udp, port)) return false; if (!port_filters_match(&dp->pf_udp, port)) return false;
break; break;
case IPPROTO_ICMP: case IPPROTO_ICMP:
case IPPROTO_ICMPV6:
if (!icmp_filters_match(&dp->icf, icmp_type, icmp_code)) return false; if (!icmp_filters_match(&dp->icf, icmp_type, icmp_code)) return false;
break; break;
default: default:
@@ -821,7 +822,7 @@ static bool desync_get_result(uint8_t *verdict)
goto err; goto err;
} }
lua_Integer lv = lua_tointeger(params.L, -1); lua_Integer lv = lua_tointeger(params.L, -1);
if (lv & ~VERDICT_MASK) if (lv & ~VERDICT_MASK_VALID_LUA)
{ {
DLOG_ERR("desync function returned bad int result\n"); DLOG_ERR("desync function returned bad int result\n");
goto err; goto err;
@@ -836,6 +837,20 @@ err:
lua_pop(params.L, rescount); lua_pop(params.L, rescount);
return false; return false;
} }
static uint8_t verdict_aggregate(uint8_t v1,uint8_t v2)
{
uint8_t verdict_action = v1 & VERDICT_MASK;
switch (v2 & VERDICT_MASK)
{
case VERDICT_MODIFY:
if (verdict_action == VERDICT_PASS) verdict_action = VERDICT_MODIFY;
break;
case VERDICT_DROP:
verdict_action = VERDICT_DROP;
break;
}
return v1 & ~VERDICT_MASK | verdict_action | v2 & VERDICT_PRESERVE_NEXT;
}
static uint8_t desync( static uint8_t desync(
struct desync_profile *dp, struct desync_profile *dp,
uint32_t fwmark, uint32_t fwmark,
@@ -1031,14 +1046,8 @@ static uint8_t desync(
} }
if (!desync_get_result(&verdict_func)) if (!desync_get_result(&verdict_func))
goto err; goto err;
switch (verdict_func & VERDICT_MASK)
{ verdict = verdict_aggregate(verdict, verdict_func);
case VERDICT_MODIFY:
if (verdict == VERDICT_PASS) verdict = VERDICT_MODIFY;
break;
case VERDICT_DROP:
verdict = VERDICT_DROP;
}
} }
else else
DLOG("* lua '%s' : payload_type '%s' does not satisfy filter\n", instance, l7payload_str(l7payload)); DLOG("* lua '%s' : payload_type '%s' does not satisfy filter\n", instance, l7payload_str(l7payload));
@@ -1057,7 +1066,7 @@ static uint8_t desync(
} }
} }
if (verdict == VERDICT_MODIFY) if ((verdict & VERDICT_MASK)==VERDICT_MODIFY)
{ {
// use same memory buffer to reduce memory copying // use same memory buffer to reduce memory copying
// packet size cannot grow // packet size cannot grow
@@ -1073,16 +1082,12 @@ static uint8_t desync(
} }
else else
{ {
b = lua_reconstruct_dissect(params.L, -1, mod_pkt, len_mod_pkt, false, false, IPPROTO_NONE, false); b = lua_reconstruct_dissect(params.L, -1, mod_pkt, len_mod_pkt, false, false, IPPROTO_NONE, !!(verdict & VERDICT_PRESERVE_NEXT));
lua_pop(params.L, 2); lua_pop(params.L, 2);
if (!b) if (!b)
{ {
DLOG_ERR("failed to reconstruct packet after VERDICT_MODIFY\n"); DLOG_ERR("failed to reconstruct packet after VERDICT_MODIFY\n");
// to reduce memory copying we used original packet buffer for reconstruction. verdict = VERDICT_PASS;
// it may have been modified. windows and BSD will send modified data despite of VERDICT_PASS.
// force same behavior on all OS
// it's LUA script error, they passed bad data
verdict = VERDICT_DROP;
goto ex; goto ex;
} }
DLOG("reconstructed packet due to VERDICT_MODIFY. size %zu => %zu\n", dis->len_pkt, *len_mod_pkt); DLOG("reconstructed packet due to VERDICT_MODIFY. size %zu => %zu\n", dis->len_pkt, *len_mod_pkt);

View File

@@ -3827,6 +3827,8 @@ static void lua_init_const(void)
{"VERDICT_PASS",VERDICT_PASS}, {"VERDICT_PASS",VERDICT_PASS},
{"VERDICT_MODIFY",VERDICT_MODIFY}, {"VERDICT_MODIFY",VERDICT_MODIFY},
{"VERDICT_DROP",VERDICT_DROP}, {"VERDICT_DROP",VERDICT_DROP},
{"VERDICT_MASK",VERDICT_MASK},
{"VERDICT_PRESERVE_NEXT",VERDICT_PRESERVE_NEXT},
{"DEFAULT_MSS",DEFAULT_MSS}, {"DEFAULT_MSS",DEFAULT_MSS},