bol-van/zapret2
GitHub: bol-van/zapret2
一款可编程的跨平台反 DPI 工具,通过 Lua 脚本实现灵活的审查绕过与流量混淆策略。
Stars: 1905 | Forks: 62
## 英文
[手册](manual.en.md)
## 为什么需要这个
一款自主的对抗 DPI 的工具,无需连接任何第三方服务器。它可以帮助绕过 HTTP(S) 网站的封锁或限速,以及针对 TCP 和 UDP 协议的特征分析(例如用于封锁 VPN)。它也可用于部分透明混淆协议。
该项目主要针对运行 OpenWrt 的低功耗嵌入式设备——路由器。同时也支持传统的 Linux 系统、FreeBSD、OpenBSD 和 Windows。在某些情况下,也可以将其适配到不同的固件中。
[完整手册](manual.md)
## 这与 zapret1 有何不同
zapret2 是 zapret 项目的进一步发展。
其主要组件 *nfqws1* 的问题在于它充斥着过多的选项,并且在监管者与用户之间对抗日益加剧的环境下,无法提供足够的流量处理灵活性。
绕过 DPI 需要越来越精细和特定的干预手段,这些手段会随着时间而改变,旧的手段则会失效。
策略是指控制 DPI 攻击场景的程序。在 *nfqws1* 中,它们被硬编码在 C 代码中。编写 C 代码并非易事,需要开发者具备足够的资质和时间。
*nfqws2* 的目标是让任何具备网络知识、了解 DPI 漏洞(或者至少知道在哪个领域寻找漏洞)并掌握基本编程技能的人都能编写策略程序。
*nfqws2* 保留了几乎相同的功能——协议识别、重组、解密、配置文件管理、hostlists(主机列表)、ipset 以及基本过滤。
但它完全失去了独立处理流量的能力。“欺骗”的部分被转移到了 Lua 脚本语言中。
Lua 代码从 C 代码处接收以树状结构(解析树)呈现的传入数据包的结构化表示,类似于你在 Wireshark 中看到的那样。
同时接收的还有某些协议(tls, quic)的部分重组或解密结果。
C 代码提供了辅助函数,允许发送数据包、处理二进制数据、解析 TLS、查找标记位置等。
这里有一个用 Lua 编写的辅助库,以及一个现成的 DPI 攻击程序(策略)库,它以更扩展且更灵活的方式实现了 *nfqws1* 的功能。
你随时可以拿去并添加自己的东西。其意义在于,任何懂网络包的人都能参与到对抗 DPI 的斗争中来。
可以“试探”它,验证自己的想法。然后与朋友分享你的“一键”解决方案。
zapret2 是为这些爱好者准备的工具。但这并不是给小白准备的现成解决方案。该项目的目标并不是让一切对所有人都变得简单。
作者认为,由于客观原因,这原则上是不可能的。
## 从哪里开始
我们希望避免在主页上出现[长篇大论](manual.md)。因此,我们将从 *nfqws2* 的启动方式和移植 *nfqws1* 策略的方法开始——即如何在 *nfqws2* 中实现 *nfqws1* 中能做到的事情。
当你理解了它是如何工作的,你可以查看“底层”的 Lua 代码。分析它的工作原理,并参考[长篇大论](manual.md)作为指南,尝试编写自己的东西。
### 流量处理机制
最初,任何操作系统中的网络流量都出现在内核中。第一个任务是从那里提取它并将其重定向到 *nfqws2* 进程。
这个任务在 Linux 中通过 iptables 和 nftables 解决,在 BSD 中通过 ipfw 和 pf 解决,在 Windows 中通过 windivert 解决。
将流量从内核重定向出来的过程会消耗大量资源,因此最好直接在内核中过滤掉尽可能多的流量。
为了在 Linux 上进行实验,可以从以下 nftables 规则开始,它们将连接的初始数据包重定向到 TCP 端口 80、443 和 UDP 端口 443,并将其发送到编号为 200 的 NFQUEUE。
```
nft delete table inet ztest
nft create table inet ztest
nft add chain inet ztest post "{type filter hook postrouting priority 101;}"
nft add rule inet ztest post meta mark and 0x40000000 == 0 tcp dport "{80,443}" ct original packets 1-12 queue num 200 bypass
nft add rule inet ztest post meta mark and 0x40000000 == 0 udp dport "{443}" ct original packets 1-12 queue num 200 bypass
sysctl net.netfilter.nf_conntrack_tcp_be_liberal=1
nft add chain inet ztest pre "{type filter hook prerouting priority -101;}"
nft add rule inet ztest pre meta mark and 0x40000000 == 0 tcp sport "{80,443}" ct reply packets 1-12 queue num 200 bypass
nft add rule inet ztest pre meta mark and 0x40000000 == 0 udp sport "{443}" ct reply packets 1-12 queue num 200 bypass
nft add chain inet ztest predefrag "{type filter hook output priority -401;}"
nft add rule inet ztest predefrag "mark & 0x40000000 != 0x00000000 notrack"
```
在 Windows 中,拦截功能直接内置在名为 *winws2* 的 Windows 引擎代码中。它使用 windivert 驱动程序。
要拦截整个端口,使用参数 `--wf-tcp-in`、`--wf-tcp-out`、`--wf-udp-in`、`--wf-udp-out`。
它们分别对应 tcp 或 udp 协议,以及传入或传出的数据包。例如,`--wf-tcp-out=80,443`。
为了进行更精确的拦截,可以使用 windivert 过滤语言编写过滤器。它类似于 tcpdump 或 wireshark 的过滤语言。
过滤器通过 `--wf-raw-part` 参数传递给 *winws2*。过滤器构造器将所有指定的拦截选项合并为一个原始过滤器,并启动 windivert 拦截。
遗憾的是,windivert(以及 BSD ipfw 和 pf)最致命的缺陷是缺乏对连接中数据包编号的限制(iptables 中的 connbytes,nftables 中的 ct packets)。
windivert 根本不跟踪连接。因此,如果拦截整个端口,那么指定方向上的整个连接都会被拦截,如果那里传输了许多兆字节的数据,这对处理器来说是一个沉重的负担。
因此,尽可能编写自己的 windivert 过滤器,至少部分检查 payload 类型。*winws2* 可以执行进一步的过滤。
接下来,需要在 root 权限下使用命令行参数启动 *nfqws2*。它们的构建方式大致如下:
```
nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-antidpi.lua \
--filter-tcp=80,443 --filter-l7=tls,http \
--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,rndsni,dupsid \
--payload=http_req --lua-desync=fake:blob=fake_default_http:tcp_md5 \
--payload=tls_client_hello,http_req --lua-desync=multisplit:pos=1:seqovl=5:seqovl_pattern=0x1603030000
```
此示例假设同一目录中包含文件 `zapret-lib.lua`(Lua 辅助库)和 `zapret-antidpi.lua`(基本策略库)。
`--lua-init` 可以包含字符串形式的 Lua 代码。这便于编写简单的代码,例如将常量赋值给变量,而无需为此琐事创建文件。
或者如果参数值以 `@` 开头,则挂载文件。`--lua-init` 中的代码在启动时执行一次。
接下来是指定的 `--lua-desync` 参数。它们包含在处理通过多策略配置文件的每个数据包时调用的 Lua 函数名称。
冒号后以及通过冒号分隔的是该函数的参数,格式为 `param[=value]`。示例中实现的策略是
```
nfqws --qnum 200 --debug \
--filter-tcp=80,443 --filter-l7=tls,http \
--dpi-desync=fake,multisplit --dpi-desync-fooling=md5sig --dpi-desync-split-pos=1,midsld \
--dpi-desync-split-seqovl=5 --dpi-desync-split-seqovl-pattern=0x1603030000 \
--dpi-desync-fake-tls-mod=rnd,rndsni,dupsid
```
立即引人注目的是“payload”概念的存在。在 *nfqws1* 中,只有参与配置文件过滤的连接协议。
它们在 *nfqws2* 中仍然存在,但引入了另一个概念——payload 类型。Payload 是当前数据包的内容。
Payload 类型是包含在数据包或数据包组中的数据类型。例如,连接协议可以是 tls,而 payload 可以是 tls_client_hello、tls_server_hello、unknown。
另一个重要的区别是没有严格定义的去同步化阶段。你以前写成 `fake,multisplit` 的内容,现在由两个顺序调用的 Lua 函数实现。根据数据包通过和操作的逻辑,函数数量可以根据需要设置,并且每个函数都可以有自己的参数。
甚至可以用不同的参数多次调用同一个函数。例如,可以发送多个 fake,并且带有不同的 fooling。
具体的 `--lua-desync` 函数调用称为 instance(实例)。实例是函数名、配置文件内调用编号和配置文件编号本身的绑定。
这就像一个可以用不同参数运行多次的程序。
另一个重要的区别是通过 `zapret-lib.lua` 支持自动 TCP 分段。你不再需要考虑发送的 TCP 数据包的大小。
每个连接都会跟踪 MSS。如果数据包不适合 MSS,则执行分段。
例如,在发送带有 kyber 的 TLS fake 时可能会发生这种情况。或者如果你切割 kyber TLS,使得其中一部分的大小为 1600 字节,这显然不适合 MTU。或者如果你设置了 seqovl=10000。在 *nfqws1* 中,这样的值会导致错误。Lua 函数 `rawsend_dissect_segmented` 将发送多个 TCP 段,起始 sequence 为 -10000,总大小为 10000 字节,其中最后一个将包含原始消息的片段。
在 *nfqws2* 中,没有硬编码的自定义 fake 参数,如 `--dpi-desync-fake-tls`、`dpi-desync-fake-http` 等。
取而代之的是 blob。Blob 是 *string* 类型的 Lua 变量,包含任意长度的二进制数据块。从 1 个字节到千兆字节。
*nfqws2* 自动初始化带有标准 fake(tls, http, quic)的 blob,就像在 *nfqws1* 中那样。
Blob 可以在 desync 函数参数中直接指定为 hex 字符串,或者通过参数 `--blob=name:0xHEX|[+ofs]@filename` 在启动时预加载。
至于多策略配置文件和 hostlists,它们几乎保持不变。除了 autolist 的一个细微差别。
现在,带有 autolist 的配置文件只接管那些已知主机的连接。在主机未知之前,它们会被跳过。
在 *nfqws1* 中,它们会落入带有 autolist 的配置文件。
```
nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-antidpi.lua \
--filter-tcp=80 --filter-l7=http --hostlist=mylist1.txt --lua-desync=multisplit --new \
--filter-tcp=80 --filter-l7=http --hostlist-exclude=mylist2.txt --lua-desync=fake:blob=0x00000000:ip_ttl=5:ip6_ttl=3 --lua-desync=multidisorder:pos=5,endhost-1 --new \
--filter-tcp=443 --filter-l7=tls --hostlist=mylist1.txt --lua-desync=multidisorder
```
*nfqws1* 的参数 start/cutoff(`--dpi-desync-start`、`--dpi-desync-cutoff` 等)现在称为 ranges。
只剩下 2 个 range:`--in-range` 和 `--out-range`。它们分别对应传入和传出方向。
是的,现在可以完全像处理传出数据包一样处理传入数据包。还有用于服务器的特殊模式——`--server`,它调整源/目标 IP 地址和端口的解释,以便 ipset 和过滤器正常工作。
range 指定为 `mX-mY`、`mX
标签:FreeBSD, IP 地址批量处理, nfqws, OpenWrt, rizin, TCP/IP 协议, UDP 协议, VPN 对抗, 互联网审查绕过, 反 DPI, 客户端加密, 客户端加密, 嵌入式设备, 抗封锁, 流量伪装, 流量劫持, 深度包检测规避, 签名分析对抗, 网络安全, 网络安全, 网络流量混淆, 路由器去广告, 隐私保护, 隐私保护