一种抛弃随机数基于数独的代理协议,开启了明文 / 低熵 / 用户自定义特征代理时代
理论上解决了上下行对等的问题
Sudoku 协议目前已被 Mihomo 内核支持!
SUDOKU 是一个基于4x4数独设题解题的流量混淆协议。它通过将任意数据流(数据字节最多有256种可能,4x4数独的非同构体有288种)映射为以4个Clue为题目的唯一可解数独谜题,每种Puzzle有不少于一种的设题方案,随机选择的过程使得同一数据编码后有多种组合,产生了混淆性。
将原始数据字节映射为数独题目后发给另一端,对方解出题目即可得到原始数据,由于映射的多样性,使得用户可以自由决定流的外观。
版本要求: - 基于 Mihomo 内核的客户端:Mihomo > v1.19.21 - 官方安卓客户端 Sudodroid:Sudodroid >= v0.2.4 - 官方桌面客户端 sudoku4x4: sudoku4x4 >= v0.0.9
非常轻量的swift原生sudoku实现,占用与性能相较mihomo内核的iOS应用有不俗提升,且由sudoku官方参与sudoku协议的开发,更加原生
传统代理协议的填充方案是决定一个padding length,接受者根据length长度直接忽略后续填充字节。 sudoku的填充方案是根据数独是否能被唯一解出或是否为可解数独而过滤非法字节,则实现了可以在任意位置、不协商padding length的情况下的任意填充(只需填充不可解数独字节),外观特征显著小于常规填充方案。
不同于传统的随机噪音混淆,本协议通过多种掩码方案,可以将数据流映射到完整的ASCII可打印字符(这只是微不足道的、可选的一种罢了,你的特征你来决定)中,抓包来看是完全的明文数据(特指在这种情况下,而非全部情况下,sudoku不是专为明文而生,明文只是附带的一个选择罢了),亦或者利用其他掩码方案,使得数据流的熵足够低。 * 动态填充: 在任意时刻任意位置填充任意长度非数据字节,隐藏协议特征。 * 数据隐藏: 填充字节的分布特征与明文字节分布特征基本一致(65%~100%的ASCII占比),可避免通过数据分布特征识别明文。 * 低信息熵: 整体字节汉明1约在3.0/5.0(低熵模式下),低于GFW Report提到的会被阻断的3.4~4.6。 * 自由暖暖: 用户可以随意定义想要的字节样式,我们不推荐某一种,正是大家混着用才能更好规避审查。
*注:
prefer_ascii下ASCII占比大于98%,汉明1在4附近。prefer_entropy下不定义自定义xvp时ASCII占比在65%,汉明1在3附近。
enable_pure_downlink 设为 false 后,下行会把 AEAD 密文拆成 6bit 片段,复用原有的填充池与 ASCII/entropy/customised 偏好,降低下行开销;上行保持sudoku本身协议,下行特征此时与上行保持一致。此模式必须开启 AEAD。在混淆层之下,协议可选的采用 AEAD 保护数据完整性与机密性。 * 算法支持: AES-128-GCM 或 ChaCha20-Poly1305。 * PFS + Key Update:每条连接派生独立会话密钥,并在长连接中自动轮转子密钥。 * 防重放:握手阶段做短 TTL 的 nonce 严格去重(并包含时间戳偏移校验),阻断窗口内重放。
当服务器检测到非法的握手请求、超时的连接或格式错误的数据包时,不直接断开连接,而是将连接无缝转发至指定的诱饵地址(如 Nginx 或 Apache 服务器)。探测者只会看到一个普通的网页服务器响应。
Fallback 的主要价值不止是“回落到网页”,更常见的是把它当作链式代理/中转:用一个“外层 Sudoku 服务端”做入口(伪装/承压/抗探测),在握手判定失败时把连接转发到 fallback_address;而 fallback_address 指向的是内层的另一个 Sudoku 服务端,由它来接收并完成真实的 Sudoku 握手与转发。
推荐搭法(两层 Sudoku):
1. 内层(真实)Sudoku 服务端:监听一个内网端口(例如 0.0.0.0:8443),配置为你真正要用的与真实客户端配套的 key / aead / httpmask 等。
2. 外层(入口)Sudoku 服务端(跳板):监听公网端口,并设置:
- "suspicious_action": "fallback"
- "fallback_address": "x.x.x.x:8443"(指向内层ip:port)
- key 填一个不同于内层的“假 key”(这样正常客户端连到外层时会握手失败,从而触发 fallback 中转到内层),或者相同的key不同的ascii偏好。
3. 客户端:server_address 填外层公网地址,但 key 使用内层的真实 key且与内层配套。
这样客户端看起来“连的是外层”,但实际握手与数据通道都在内层完成;外层只负责在握手失败时把已读到的前缀字节按顺序重放给内层,然后做双向转发。 (~~当然中间跳板也是完整的 sudoku 服务器~~)
go build -o sudoku cmd/sudoku-tunnel/main.go
配置模板与字段说明请看: - configs/README.zh_CN.md - configs/README.md
模板:
- configs/server.config.json
- configs/client.config.json
本地构建:
docker build -t sudoku:local .
运行(首次启动自动生成配置):
docker run --rm -p 8080:8080 -p 8081:8081 -v sudoku-data:/etc/sudoku sudoku:local
容器在 /etc/sudoku/server.config.json / /etc/sudoku/keys.env 不存在时会自动生成,并在日志里输出客户端所需的私钥(AVAILABLE_PRIVATE_KEY)。
如果你想自带配置,也可以直接挂载:
docker run --rm -p 8080:8080 -p 8081:8081 -v "$PWD/server.config.json:/etc/sudoku/server.config.json:ro" sudoku:local
注意:Key一定要用sudoku专门生成
务必先生成KeyPair
$ ./sudoku -keygen
Available Private Key: b1ec294d5dba60a800e1ef8c3423d5a176093f0d8c432e01bc24895d6828140aac81776fc0b44c3c08e418eb702b5e0a4c0a2dd458f8284d67f0d8d2d4bfdd0e
Master Private Key: 709aab5f030c9b8c322811d5c6545497c2136ce1e43b574e231562303de8f108
Master Public Key: 6e5c05c3f7f5d45fcd2f6a5a7f4700f94ff51db376c128c581849feb71ccc58b
你需要将Master Public Key填入服务端配置的key,然后复制Available Private Key,填入客户端的key。
如果你需要生成更多与此公钥相对的私钥,请使用-more参数 + 已有的私钥/'Master Private Key':
$ ./sudoku -keygen -more 709aab5f030c9b8c322811d5c6545497c2136ce1e43b574e231562303de8f108
Split Private Key: 89acb9663cfd3bd04adf0001cc7000a8eb312903088b33a847d7e5cf102f1d0ad4c1e755e1717114bee50777d9dd3204d7e142dedcb023a6db3d7c602cb9d40e
将此处的Split Private Key填入客户端配置的key。
指定配置文件路径运行程序
./sudoku -c server.config.json
./sudoku -c client.config.json
[!NOTE]\ 此软件仅用于教育和研究目的。用户需自行遵守当地网络法规。
$ claude mcp add sudoku \
-- python -m otcore.mcp_server <graph>