Freedom(fragment、noises)
Freedom 是一个出站协议,可以用来向任意网络发送(正常的) TCP 或 UDP 数据。
WARNING
该出站在服务器端和反向代理端存在默认安全策略,可能会阻止一些目标,放行方式见下文 finalRules。
OutboundConfigurationObject
OutboundConfigurationObject 对应 OutboundObject 中的 settings 项。
{
"outbounds": [
{
// ...
"protocol": "freedom",
"settings": {
"domainStrategy": "AsIs",
"redirect": "127.0.0.1:3366",
"userLevel": 0,
"fragment": {
"packets": "tlshello",
"length": "100-200",
"interval": "10-20" // 单位ms
},
"noises": [
{
"type": "base64",
"packet": "7nQBAAABAAAAAAAABnQtcmluZwZtc2VkZ2UDbmV0AAABAAE=",
"delay": "10-16"
}
],
"proxyProtocol": 0,
"finalRules": [
{
"action": "block",
"network": "tcp",
"port": "22,25,465,587"
},
{
"action": "block",
"ip": ["geoip:cn"]
}
]
}
}
]
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
domainStrategy: "AsIs"
"UseIP" | "UseIPv6v4" | "UseIPv6" | "UseIPv4v6" | "UseIPv4"
"ForceIP" | "ForceIPv6v4" | "ForceIPv6" | "ForceIPv4v6" | "ForceIPv4"
默认值 "AsIs"。
所有参数含义均约等于 sockopt 中的 domainStrategy.
在这里使用 AsIs 才可以把域名交给后面的 sockopt 模块,如果在这里设置非 AsIs 导致域名被解析为具体 IP 会使后续的 sockopt.domainStrategy 以及其相关的 happyEyeballs 失效。(如果不调整这两个设置则没有负面影响)
Freedom 在发送 UDP 时出于一些原因无视 sockopt 中的 domainStrategy 并在默认状态下强制偏好 IPv4.
redirect: address_port
Freedom 会强制将所有数据发送到指定地址(而不是 inbound 指定的地址)。
其值为一个字符串,样例:"127.0.0.1:80",":1234"。
当地址不指定时,如 ":443",Freedom 不会修改原先的目标地址。 当端口为 0 时,如 "xray.com: 0",Freedom 不会修改原先的端口。
userLevel: number
用户等级,连接会使用这个用户等级对应的 本地策略。
userLevel 的值, 对应 policy 中 level 的值。 如不指定, 默认为 0。
fragment: map
一些键值对配置项,用于控制发出的 TCP 分片,在某些情况下可以欺骗审查系统,比如绕过 SNI 黑名单。
"length"和"interval" 均为 Int32Range 类型
"packets":支持两种分片方式 "1-3" 是 TCP 的流切片,应用于客户端第 1 至第 3 次写数据。"tlshello" 是 TLS 握手包切片。
"length":分片包长 (byte)
"interval":分片间隔(ms)
当其为 0 且设置 "packets": "tlshello" 时,被分片的 Client Hello 将会在一个TCP包中发送(如果其原始大小未超过MSS或MTU导致被系统自动分片)
noises: array
UDP noise, 用于在发出UDP连接前发出一些随机数据作为“噪声”,出现该结构体则视为启用,可能可以欺骗嗅探器,也可能破坏正常连接。Use at your own risk. 出于这个原因,它会绕过53端口因为这会破坏 DNS
为一个数组,可以定义多个要发出的噪声数据包,数组中单个元素定义如下
"type": 噪声数据包类型,目前支持"rand"(随机数据), "str"(用户自定义字符串), "base64"(base64编码过的自定义二进制数据)
"packet": 基于前面的 type 要发送的数据包内容
- 当
type为 rand 时,这里指定随机数据的长度 可以是固定值"100"或者浮动值"50-150" - 当
type为 str 时,这里指定要发送的字符串 - 当
type为 hex 时,这里指定以 hex 形式表示的的二进制数据 - 当
type为 base64 时,这里指定 base64 过的二进制数据
"delay": 延迟,单位毫秒。发送该噪声包后核心会等待该时间后再发送下一个噪声包或真实数据,默认不等待,为 Int32Range 类型
proxyProtocol: number
PROXY protocol 通常配合 redirect 重定向到开启了 PROXY protocol 协议的 Nginx 或其他后端服务中。如果后端服务不支持 PROXY protocol 协议,连接将会被断开。
proxyProtocol 的值为 PROXY protocol 版本号,可选 1 或 2,如不指定,默认为 0 不启用。
finalRules: [FinalRuleObject]
按顺序匹配 Freedom 最终出站规则,用于放行或阻止连接目标。
相比在 routing 中封锁,finalRules 位于 Freedom 最终出站阶段:在解析出最终 IP 后、拨号前匹配;此外 UDP 在收发时还会逐包匹配,因此更严谨、更彻底;每条规则匹配耗时约 50~150ns。
注意:只要 Freedom 需要执行 finalRules,当 domainStrategy 为 AsIs 且目标为域名时,Freedom 仍会先通过操作系统 DNS 将目标解析为 IP,再执行规则匹配。此时目标已不再是域名,后续的 sockopt.domainStrategy 及其 happyEyeballs 不再生效。
WARNING
服务器端和反向代理端存在默认兜底安全策略:
若未命中任何显式规则,则使用内置兜底规则:来自 VLESS 反向代理的流量默认阻止所有目标;来自 VLESS、VMess、Trojan、Shadowsocks、Hysteria 或 WireGuard 入站的流量默认阻止私有及保留 IP;其它流量默认全部放行。
若服务器端需要允许客户端访问某些内网服务,应显式配置 allow 规则,并尽量只放行必要的 network、ip 和 port。
若服务器端还需要依赖域名传递给 sockopt 的特性(例如 sockopt.domainStrategy 或 happyEyeballs),则不能继续依赖这套默认安全策略。可将第一条规则配置为不带任何匹配条件的 allow,以恢复此前行为;这样也等同于关闭这套默认安全策略,应自行评估安全影响。
FinalRuleObject
{
"action": "block",
"network": "tcp,udp",
"port": "53,443",
"ip": ["10.0.0.0/8", "2001:db8::/32"],
"blockDelay": "30-90"
}2
3
4
5
6
7
规则中的各匹配条件为与关系;省略某个条件时,表示对此条件不作限制。
action: "allow" | "block"
定义规则命中后的动作。
allow: 放行目标。block: 阻止目标。
network: "tcp" | "udp" | "tcp,udp"
匹配网络类型。当连接方式是指定方式时,此规则生效。也可以写成字符串数组,如 ["tcp", "udp"]。省略时匹配所有网络。
port: number | string
目标端口范围,写法与 路由规则中的 port 一致。省略时匹配所有端口。
ip: [string]
一个数组,数组内每一项代表一个 IP 范围。当某一项匹配目标 IP 时,此规则生效。写法与 路由规则中的 ip 一致。省略时匹配所有 IP。
blockDelay: string
设置阻止规则命中后的黑洞持续时间。
当规则的 action 为 block 且命中目标时,Freedom 会让连接进入黑洞状态,并在这段时间结束后关闭连接。单位为秒,可以写成固定值或范围,例如 30 或 30-90。省略时默认为 30-90 即此范围内随机一个值。