Skip to content

数据包伪装系统(Finalmask)

位置:传输机制层 | 难度:较难 | 前置深度包检测机制源码证据transport/internet/finalmask/ 全部 16 个子模块


1. 系统定位

Finalmask 是 xray-core 的数据包伪装层——一个可组合、可链式堆叠的混淆框架。当代理流量在网络层面传输时,finalmask 在数据包上应用多层变换,使流量在 DPI 系统中表现为特定已知协议(DNS、DTLS、WeChat 视频、WireGuard 等)或完全随机的不可识别格式。

每层可选、可组合、可排序。用户配置决定了哪些伪装层以何种顺序生效。


2. 架构核心

源码位置:transport/internet/finalmask/finalmask.go

Finalmask 通过两个接口和两个管理器组织所有伪装模块:

go
type Udpmask interface {
    UDP() bool
    WrapPacketConnClient(net.PacketConn) (net.PacketConn, error)
    WrapPacketConnServer(net.PacketConn) (net.PacketConn, error)
}

type Tcpmask interface {
    TCP() bool
    WrapConnClient(net.Conn) (net.Conn, error)
    WrapConnServer(net.Conn) (net.Conn, error)
}

UdpmaskManager / TcpmaskManager 按配置顺序链式调用各 mask 的 Wrap 方法,每一层返回的包装连接作为下一层的输入。最内层是原始 socket,最外层最终交给代理协议使用。


3. 伪装模块分类

3.1 载荷混淆 — 加密/编码数据内容

Salamander(蝾螈)

源码位置:finalmask/salamander/ | 核心文件:salamander.go

原理:每包独立的 XOR 混淆,使用 BLAKE2b-256 从预共享密钥 + 8 字节随机盐派生加密流。

数据包格式

[8 bytes Salt] [XOR 混淆后的载荷]
go
func (s *SalamanderObfuscator) Obfuscate(b []byte) {
    salt := random(8)
    key := blake2b256(psk || salt)   // 32 字节派生密钥
    for i := range payload {
        payload[i] ^= key[i % 32]
    }
    // 输出:salt[0:8] + 混淆后的payload
}

对 DPI 的对抗:相同明文产生不同密文(盐不同)。8 字节盐集成到头管理层,被伪装头包裹。BLAKE2b 密钥派生使每个包的 XOR 模式独立。

Sudoku

源码位置:finalmask/sudoku/ | 核心文件:codec.go, table.go

原理:将每个字节编码为 4 个"提示"字节(从 4x4 数独网格派生),使流量表现为特定字节分布。

三种字节布局

布局输出范围效果
ASCII0x20-0x7E(可打印 ASCII)模仿 HTTP 明文
Entropy0x00-0x8F模仿任意二进制
Custom用户定义模式精确控制字节分布

编码过程

  1. 从密码 SHA-256 生成 288 个 4x4 数独网格
  2. 对每个网格,计算哪些 4 位置组合能唯一标识该网格
  3. 输入字节值选择对应的网格,输出该网格的 4 个位置坐标
  4. 每个位置的字节值 = base + value,其中 base 由布局类型决定

Packed 模式(TCP 下行):使用 6-bit 编码替代 4-byte 编码,将开销从 4x 降到约 1.33x。

mKCP AES-128-GCM

源码位置:finalmask/mkcp/aes128gcm/

标准 AES-128-GCM 认证加密。每包生成随机 Nonce (12 字节),前置在数据包前。密码从配置的 Password 经 SHA-256 截断为 16 字节密钥。

mKCP Original(XOR 链)

源码位置:finalmask/mkcp/original/

轻量级 XOR 混淆:前置 4 字节 FNV-32a 校验和 + 2 字节长度,然后对载荷应用 4 字节向前/向后 XOR 链。提供 Go 通用和 amd64 汇编两个版本。


3.2 外观伪装 — 添加已知协议包头

每个外观伪装模块在 UDP 数据包前添加固定大小的协议特征头,使包在 DPI 系统中匹配已知白名单协议。

模块包头大小伪装目标头部特征
header/dns12B + 域名段DNS 查询 (RFC 1035)随机 Transaction ID + A-record 查询
header/dtls13BDTLS 1.2 应用数据17 FE FD + epoch + seq
header/srtp4B加密 RTP(VoIP)B5 E8 + 序列号
header/utp4BμTP(BitTorrent)连接 ID + 类型/扩展字节
header/wechat13B微信视频通话A1 08 + 序列号 + 固定数据
header/wireguard4BWireGuard 握手04 00 00 00

选择依据:这些协议的共同特征是——它们在绝大多数网络中不被阻断(VoIP、DNS、微信都是基础通信服务),且 DPI 系统通常不对它们进行深度内容检查。

自定义头(header/custom)

源码位置:finalmask/header/custom/ | 核心文件:evaluator.go

最灵活的伪装模块。用户通过 Protobuf 配置定义任意字节序列作为握手头。支持表达式求值器:

  • 运算符:concat, slice, xor16, xor32, be16, be32, le16, le32, pad, truncate, add, sub, and, or, shl, shr
  • 变量:src_port_u16, src_ip4_u32, dst_port_u16, dst_ip4_u32(连接元数据)
  • 状态存储:TTL 键值对,同一客户端地址的连接共享状态

UDP 独立模式:对 UDP 执行两步握手——客户端发送请求头,服务端验证并返回响应头,验证通过后才开始传输数据。


3.3 载体传输 — 将数据嵌入另一个协议

xDNS

源码位置:finalmask/xdns/ | 核心文件:dns.go(581行), client.go(417行), server.go(512行)

将数据编码为 DNS 查询/响应:

  1. 客户端将载荷 base32 编码
  2. 分片为 DNS 标签段(每段 ≤ 63 字节)
  3. 构造 DNS 查询包:<编码数据>.<配置域名>
  4. 服务端接收查询 → 解码 base32 → 交给上层协议
  5. 回复数据封装为 DNS Answer Records(支持 TXT、A、AAAA 类型)
  6. 使用 record_transport.go 进行分段/多路复用

限制:每包载荷约 300 字节(DNS 域名长度限制)。不适合大流量场景,但几乎不可能被阻断——DNS 是互联网基础设施。

xICMP

源码位置:finalmask/xicmp/ | 核心文件:client.go(346行), server.go(375行)

将数据编码为 ICMP Echo(Ping)包:

  1. 客户端将载荷封装为 ICMP Echo Request
  2. 服务端接收 → 解析载荷 → 返回 ICMP Echo Reply
  3. 使用滑动窗口(windowSize=1000)管理序列号
  4. 空闲时发送空载荷的 poll 消息维持通道

限制:必须是最外层伪装。需要 raw socket 权限。许多云环境限制 ICMP 流量。


3.4 流量混淆 — 改变包大小和时序

Noise

源码位置:finalmask/noise/conn.go

在首个数据包之前发送配置数量(Burst)的随机内容包,包间有随机延迟。之后使用 TTL 清除状态。目的:混淆 DPI 对"连接首个数据包"的时序和长度分析。

Fragment

源码位置:finalmask/fragment/conn.go

将 TCP 写入拆分为多个小片段。对 TLS 有专门处理:

  • 检测 TLS Handshake(0x16)记录
  • 将记录体拆分为多个小 TLS 记录
  • 每个片段可有随机延迟(DelayMin/DelayMax
  • 限制每写入的最大拆分数(MaxSplitMin/MaxSplitMax

对 DPI 的对抗:针对检查 TLS ClientHello 大小/时序的 DPI 规则。标准 ClientHello 是一个完整的 TLS 记录(通常 200-500B),分片后变成多个小记录,破坏 DPI 的协议识别。


4. 伪装链的组合策略

使用场景推荐组合原理
UDP 流 + 严格 DPI[dns header] → [salamander]外层看起来是 DNS 查询,内层载荷加密
TCP 流 + 规避 TLS 指纹[fragment] → [custom header]拆分 TCP 写入,添加自定义握手头
低带宽隐蔽信道[xdns][xicmp]完全嵌入 DNS/ICMP 协议内
高带宽 + 最大伪装[noise] → [dtls header] → [aes128gcm] → [sudoku]噪声前置 + DTLS 外观 + AES 加密 + 字节编码

5. 源码文件索引

目录核心文件功能
finalmask/finalmask.goUdpmask/Tcpmask 接口 + Manager 链式调度
finalmask/fragment/conn.goTCP 写入分段
finalmask/salamander/salamander.goBLAKE2b XOR 混淆
finalmask/sudoku/codec.go, table.go数独字节编码
finalmask/noise/conn.go随机噪声前置
finalmask/mkcp/aes128gcm/conn.goAES-128-GCM 加密
finalmask/mkcp/original/conn.go, xor.goFNV+XOR 轻量混淆
finalmask/header/dns/conn.goDNS 查询头
finalmask/header/dtls/conn.goDTLS 记录头
finalmask/header/srtp/conn.goSRTP 头
finalmask/header/utp/conn.goμTP 头
finalmask/header/wechat/conn.go微信视频头
finalmask/header/wireguard/conn.goWireGuard 头
finalmask/header/custom/evaluator.go, tcp.go, udp.go自定义表达式头
finalmask/xdns/dns.go, client.go, server.goDNS 隧道
finalmask/xicmp/client.go, server.goICMP 隧道