Direct/Freedom outbound: Better Compatibility (#896)

https://github.com/XTLS/Xray-core/pull/6058
This commit is contained in:
Meow
2026-09-11 06:46:51 +08:00
committed by GitHub
parent 9125d3237c
commit b7207f4da4
30 changed files with 451 additions and 477 deletions
+16 -16
View File
@@ -4,23 +4,19 @@
Xray 内置的 DNS 模块,主要有三大用途:
- 在路由阶段,解析域名为 IP, 并且根据域名解析得到的 IP 进行规则匹配以分流。是否解析域名及分流和路由配置模块中 `domainStrategy` 的值有关,只有在设置以下两种值时,才会使用内置 DNS 服务器进行 DNS 查询:
- "IPIfNonMatch", 请求一个域名时,进行路由里面的 domain 进行匹配,若无法匹配到结果,则对这个域名使用内置 DNS 服务器进行 DNS 查询,并且使用查询返回的 IP 地址再重新进行 IP 路由匹配。
- "IPOnDemand", 当匹配时碰到任何基于 IP 的规则,将域名立即解析为 IP 进行匹配。
- 在路由阶段,解析域名为 IP, 并且根据域名解析得到的 IP 进行规则匹配以分流。<br>
是否解析域名用以分流,与路由模块中 `routing.domainStrategy` 的值有关,只有在设置以下两种值时,才会使用内置 DNS 服务器进行 DNS 查询:
- "IPIfNonMatch", 请求目标是域名且不附带 IP 时,先用其它条件进行一轮匹配,若本轮没有命中任何一条路由规则,则对这个域名使用内置 DNS 服务器进行 DNS 查询,并且使用查询返回的 IP 地址再重新进行一轮路由匹配。
- "IPOnDemand", 请求目标是域名且不附带 IP 时,当路由匹配时碰到任何基于 IP 的规则,将域名立即解析为 IP 进行匹配。
- 解析目标地址进行连接
- `freedom` 出站中,将 `domainStrategy` 设置为 `UseIP`, 由此出站发出的请求, 会先将域名通过内置服务器解析成 IP, 然后进行连接
- `sockopt` 中,将 `domainStrategy` 设置为 `UseIP`, 此出站发起的系统连接,将先由内置服务器解析为 IP, 然后进行连接
- 在出站阶段,解析目标域名,用于连接或发送给远端代理服务器
- 如在 VLESS 出站中,将 `targetStrategy` 设置为 `UseIP`,会先通过本地的内置 DNS 模块解析被代理请求的目标域名,再将解析得到的 IP 发给远端代理服务器
- 如在 VLESS 出站中,将 `sockopt.domainStrategy` 设置为 `UseIP`,会通过内置 DNS 模块解析 VLESS 服务器的域名,再连接解析得到的 IP
- 如在 Freedom 出站中,将 `sockopt.domainStrategy` 设置为 `UseIP`,会通过内置 DNS 模块解析请求的目标域名,再连接解析得到的 IP。
- 如在 Wireguard 出站中,协议不允许传递域名作为目标,可选用内置 DNS 模块解析为 IP。
- TUN/透明代理时通过路由和 DNS 出站组合,以劫持 DNS 流量到此模块;或直接对外暴露 53 端口充当递归 DNS 服务器。
::: tip TIP 1
DNS 服务器默认进入路由系统进行匹配,除非其包含 `+local` 在其中使用域名时,注意可能的回环问题,`hosts` 可能有帮助。
:::
::: tip TIP 2
只支持最基本的 IP 查询(A 和 AAAA 记录),CNAME 记录将会重复查询直至返回 A/AAAA 记录为止。其它查询不会进入内置 DNS 服务器,而是根据你在出站中的配置可以丢弃或透传给其它服务器。
:::
- TUN/透明代理时通过路由和 DNS 出站组合,以劫持 DNS 流量到此模块;或利用 [Tunnel](./inbounds/tunnel.md) 直接对外暴露 53 端口充当递归 DNS 服务器。
- 只支持最基本的 IP 查询(A 和 AAAA 记录),CNAME 记录将会重复查询直至返回 A/AAAA 记录为止。其它查询不会进入内置 DNS 服务器,而是根据你在出站中的配置可以丢弃或透传给其它服务器。
## DNS 处理流程
@@ -136,6 +132,10 @@ DNS 服务器默认进入路由系统进行匹配,除非其包含 `+local` 在
(v1.4.0+) 可以在 [日志](./log.md) 中打开 DNS 查询日志。
:::
::: tip TIP 4
DNS 服务器默认进入路由系统进行匹配,除非其包含 `+local` 在其中使用域名时,注意可能的回环问题,`hosts` 可能有帮助。
:::
> `clientIp`: string
EDNS Client Subnet 扩展中使用的 IP 地址。
@@ -297,7 +297,7 @@ DNS 回退(failover)默认是串行的,即默认仅在选中的 DNS 服务
local 模式将直接由核心向外连接,这种情况下如果地址是一个域名将交由系统本身进行解析,逻辑较为简单。
非 local 默认将视为一个从 tag 为 dns.tag(不知道在哪? 浏览器 ctrl+f 搜索 `inboundTag`) 的入站进来的请求,将经过正常的核心处理流程,可能会被路由模块分配去本地 freedom 或者其他远端出站,它将被 freedom 的 domainStrategy 解析(注意可能的回环) 或者直接以域名的形式被传送到远端根据服务端本身的解析方式解析。
非 local 模式下,DNS 查询会作为内部请求进入路由系统,其 `inboundTag` 由 DNS 配置的 `tag` 指定。若请求被路由到本地 Freedom 出站,DNS 服务器的自身的域名会按该出站的 `sockopt.domainStrategy` 解析注意可能的回环);若请求被路由到远端代理出站,则可将域名交给远端解析。
由于普通人可能难以理清其中的逻辑,建议(特别是在透明代理的环境下),直接在 DNS 模块的 host 选项中直接为带域名的服务器设置它们对应的 IP 防止出现回环。
+4 -34
View File
@@ -19,10 +19,6 @@
"settings": {},
"tag": "标识",
"streamSettings": {},
"proxySettings": {
"tag": "another-outbound-tag",
"transportLayer": false
},
"mux": {},
"targetStrategy": "AsIs"
}
@@ -67,48 +63,22 @@
此出站的传输配置。
> `proxySettings`: [ProxySettingsObject](#proxysettingsobject)
出站代理配置。
> `mux`: [MuxObject](#muxobject)
Mux 相关的具体配置。
> `targetStrategy`: "AsIs" | "UseIP" | "UseIPv6v4" | "UseIPv6" | "UseIPv4v6" | "UseIPv4" | "ForceIP" | "ForceIPv6v4" | "ForceIPv6" | "ForceIPv4v6" | "ForceIPv4"
如果此出站尝试发送一个域名请求,控制其是否被解析/如何解析为 IP 并发送
适用于 Freedom 以外的出站,控制被代理请求中的目标域名是否在本地解析为 IP,以及使用何种解析策略
默认值为 `AsIs` 即保持原样发送到远端服务器。所有参数含义均约等于 [sockopt](./transports/sockopt.md#sockoptobject) 中的 `domainStrategy`
默认值为 `AsIs`即保持目标域名原样发送到远端服务器。各策略的含义与 [sockopt](./transports/sockopt.md#sockoptobject) 中的 `domainStrategy` 基本相同
::: tip
这里控制的是**被代理的请求**,如果出站代理服务器的地址是域名,并需要为这个域名本身选择解析策略,则应配置 [sockopt](./transports/sockopt.md#sockoptobject) 中的 `domainStrategy`
Freedom 出站的域名解析策略也应配置 `sockopt.domainStrategy`
:::
### ProxySettingsObject
```json
{
"tag": "another-outbound-tag",
"transportLayer": false
}
```
> `tag`: string
当指定另一个 outbound 的标识时,此 outbound 发出的数据,将被转发至所指定的 outbound 发出。
::: danger
此选项与 [Sockopt.dialerProxy](./transports/sockopt.md#sockoptobject) 冲突,根据需要任选其一即可。
默认情况下,这种转发方式**会忽略**此出站自己的 `传输配置` (如有 XHTTP/REALITY/Sockopt...),也就是此 outbound 的 `streamSettings` 将不起作用。<br>
如果需要使用支持 `streamSettings` 方式的转发,请改用 `Sockopt.dialerProxy` 或者将这里的 `transportLayer` 设为 `true`
:::
> `transportLayer`: true | false
`true` 将此设置转化为 `Sockopt.dialerProxy` 来支持此出站的 `streamSettings`,默认为 `false` 即不转化。
### MuxObject
Mux 功能是在一条 TCP 连接上分发多个 TCP 连接的数据。实现细节详见 [Mux.Cool](../development/protocols/muxcool.md)。Mux 是为了减少 TCP 的握手延迟而设计,而非提高连接的吞吐量。使用 Mux 看视频、下载或者测速通常都有反效果。Mux 只需要在客户端启用,服务器端自动适配。Mux 的第二个用途是分发多个 UDP 连接,即 XUDP。
+78 -49
View File
@@ -1,6 +1,6 @@
# Freedomfragment、noises
Freedom 是一个出站协议,可以用来向任意网络发送(正常的) TCP 或 UDP 数据。
Freedom 是一个直连出站协议,通常也是流量的终结点:它接收上游传来的 TCP 或 UDP 流量,并直接向最终目标地址发起连接、收发数据。
::: warning
该出站在服务器端和反向代理端存在默认安全策略,可能会阻止一些目标,放行方式见下文 `finalRules`
@@ -16,9 +16,8 @@ Freedom 是一个出站协议,可以用来向任意网络发送(正常的)
{
// ...
"protocol": "freedom",
// [!code focus:29]
// [!code focus:28]
"settings": {
"domainStrategy": "AsIs",
"redirect": "127.0.0.1:3366",
"userLevel": 0,
"fragment": {
@@ -51,63 +50,34 @@ Freedom 是一个出站协议,可以用来向任意网络发送(正常的)
}
```
> `domainStrategy`: "AsIs"<br>
> "UseIP" | "UseIPv6v4" | "UseIPv6" | "UseIPv4v6" | "UseIPv4"<br>
> "ForceIP" | "ForceIPv6v4" | "ForceIPv6" | "ForceIPv4v6" | "ForceIPv4"
默认值 `"AsIs"`
所有参数含义均约等于 [sockopt](../transports/sockopt.md#sockoptobject) 中的 domainStrategy.
在这里使用 AsIs 才可以把域名交给后面的 sockopt 模块,如果在这里设置非 AsIs 导致域名被解析为具体 IP 会使后续的 sockopt.domainStrategy 以及其相关的 happyEyeballs 失效。(如果不调整这两个设置则没有负面影响)
Freedom 在发送 UDP 时出于一些原因无视 sockopt 中的 domainStrategy 并在默认状态下强制偏好 IPv4.
::: tip
Freedom 的目标域名解析策略由 [sockopt.domainStrategy](../transports/sockopt.md#sockoptobject) 控制。
:::
> `redirect`: address_port
Freedom 会强制将所有数据发送到指定地址(而不是 inbound 指定的地址
Freedom 会将连接的当前目标地址和端口改写为 `redirect`指定的地址和端口
其值为一个字符串,样例:`"127.0.0.1:80"``":1234"`
其值为一个字符串,样例:`"127.0.0.1:80"``":1234"`
当地址不指定时,如 `":443"`,Freedom 不会修改原先的目标地址。
当端口为 `0` 时,如 `"xray.com: 0"`,Freedom 不会修改原先的端口。
当端口为 `0` 时,如 `"xray.com:0"`,Freedom 不会修改原先的端口。
> `userLevel`: number
用户等级,连接会使用这个用户等级对应的 [本地策略](../policy.md#levelpolicyobject)。
userLevel 的值, 对应 [policy](../policy.md#policyobject) 中 `level` 的值。 如不指定, 默认为 0。
userLevel 的值, 对应 [policy](../policy.md#policyobject) 中 `level` 的值。如不指定默认为 0。
> `fragment`: map
> `fragment`: [FragmentObject](#fragmentobject)
一些键值对配置项,用于控制发出的 TCP 分片,在某些情况下可以欺骗审查系统,比如绕过 SNI 黑名单。
`"length"``"interval"` 均为 [Int32Range](../../development/intro/guide.md#int32range) 类型
> `noises`: \[ [NoiseObject](#noiseobject) \]
`"packets"`:支持两种分片方式 "1-3" 是 TCP 的流切片,应用于客户端第 1 至第 3 次写数据。"tlshello" 是 TLS 握手包切片
UDP noise, 用于在发出 UDP 连接前发出一些随机数据作为“噪声”,出现该结构体则视为启用,可能可以欺骗嗅探器,也可能破坏正常连接。Use at your own risk. 出于这个原因,它会绕过 53 端口因为这会破坏 DNS
`"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](../../development/intro/guide.md#int32range) 类型
为一个数组,可以定义多个要发出的噪声数据包,数组中每个元素为一个 [NoiseObject](#noiseobject)。
> `proxyProtocol`: number
@@ -115,13 +85,23 @@ PROXY protocol 通常配合 `redirect` 重定向到开启了 PROXY protocol 协
proxyProtocol 的值为 PROXY protocol 版本号,可选 `1``2`,如不指定,默认为 `0` 不启用。
> `finalRules`: \[[FinalRuleObject](#finalruleobject)\]
> `finalRules`: \[ [FinalRuleObject](#finalruleobject) \]
按顺序匹配 Freedom 最终出站规则,用于放行或阻止连接目标。
相比在 `routing` 中封锁,`finalRules` 位于 Freedom 最终出站阶段:在解析出最终 IP 后、拨号前匹配;此外 UDP 在收发时还会逐包匹配因此更严谨、彻底每条规则匹配耗时约 50~150ns
相比在 `routing` 中封锁,`finalRules` Freedom 最终出站阶段、拨号前匹配;此外 UDP 在收发时还会逐包匹配因此更严谨、彻底。(每条规则匹配耗时约 50~150ns 无需担心性能)
注意:只要 Freedom 需要执行 `finalRules`,当 `domainStrategy``AsIs` 且目标为域名时,Freedom 仍会先通过操作系统 DNS 将目标解析为 IP,再执行规则匹配。此时目标已不再是域名,后续的 `sockopt.domainStrategy` 及其 `happyEyeballs` 不再生效。
::: details 目标为域名?
目标为域名且需要执行规则时,Freedom 会在拨号前按照 `sockopt.domainStrategy` 解析域名,然后对返回的所有 IP 分别按规则顺序匹配;只要其中一个 IP 被阻止,就会阻止整个请求。
拨号成功后,Freedom 还会按规则再次检查实际连接的远端 IP。因此,拨号前解析失败或两次解析结果不一致时,仍可能在黑洞前发出 TCP 握手报文。
每个目标为域名的 UDP 数据包在发送时还会解析域名,但逐包检查只对本次选中的目标 IP 按规则顺序匹配并决定是否拦截,不会检查解析返回的所有 IP。
:::
::: tip
若此出站配置了 `sockopt.dialerProxy`,Freedom 就不再是最终出站,因此不会执行 `finalRules` 或下述默认安全策略。
:::
::: warning
服务器端和反向代理端存在默认兜底安全策略:
@@ -129,10 +109,59 @@ proxyProtocol 的值为 PROXY protocol 版本号,可选 `1` 或 `2`,如不
若未命中任何显式规则,则使用内置兜底规则:来自 VLESS 反向代理的流量默认阻止所有目标;来自 `VLESS``VMess``Trojan``Shadowsocks``Hysteria``WireGuard` 入站的流量默认阻止私有及保留 IP;其它流量默认全部放行。
若服务器端需要允许客户端访问某些内网服务,应显式配置 `allow` 规则,并尽量只放行必要的 `network``ip``port`
若服务器端还需要依赖域名传递给 `sockopt` 的特性(例如 `sockopt.domainStrategy``happyEyeballs`),则不能继续依赖这套默认安全策略。可将第一条规则配置为不带任何匹配条件的 `allow`,以恢复此前行为;这样也等同于关闭这套默认安全策略,应自行评估安全影响。
:::
### FragmentObject
```json
{
"packets": "tlshello",
"length": "100-200",
"interval": "10-20"
}
```
> `packets`: string
支持两种分片方式 "1-3" 是 TCP 的流切片,应用于客户端第 1 至第 3 次写数据。"tlshello" 是 TLS 握手包切片。
> `length`: [Int32Range](../../development/intro/guide.md#int32range)
分片包长 (byte)
> `interval`: [Int32Range](../../development/intro/guide.md#int32range)
分片间隔(ms
当其为 0 且设置 `"packets": "tlshello"` 时,被分片的 Client Hello 将会在一个 TCP 包中发送(如果其原始大小未超过 MSS 或 MTU 导致被系统自动分片)
### NoiseObject
```json
{
"type": "base64",
"packet": "7nQBAAABAAAAAAAABnQtcmluZwZtc2VkZ2UDbmV0AAABAAE=",
"delay": "10-16"
}
```
> `type`: string
噪声数据包类型,目前支持`"rand"`(随机数据), `"str"`(用户自定义字符串), `"base64"`(base64编码过的自定义二进制数据)
> `packet`: string
基于前面的 `type` 要发送的数据包内容
-`type` 为 rand 时,这里指定随机数据的长度 可以是固定值 `"100"` 或者浮动值 `"50-150"`
-`type` 为 str 时,这里指定要发送的字符串
-`type` 为 hex 时,这里指定以 hex 形式表示的的二进制数据
-`type` 为 base64 时,这里指定 base64 过的二进制数据
> `delay`: [Int32Range](../../development/intro/guide.md#int32range)
延迟,单位毫秒。发送该噪声包后核心会等待该时间后再发送下一个噪声包或真实数据,默认不等待。
### FinalRuleObject
```json
@@ -162,7 +191,7 @@ proxyProtocol 的值为 PROXY protocol 版本号,可选 `1` 或 `2`,如不
目标端口范围,写法与 [路由规则中的 `port`](../routing.md#ruleobject) 一致。省略时匹配所有端口。
> `ip`: \[string\]
> `ip`: \[ string \]
一个数组,数组内每一项代表一个 IP 范围。当某一项匹配目标 IP 时,此规则生效。写法与 [路由规则中的 `ip`](../routing.md#ruleobject) 一致。省略时匹配所有 IP。
+1 -1
View File
@@ -5,7 +5,7 @@ Loopback 是一个环回出站,用于将流量重新送回 routing 处理,
::: tip 用途
- 在只能指定出站、不能直接写 `balancerTag` 的地方,借由 Loopback 间接使用 balancer<br>
例如链式代理中的 `proxySettings``dialerProxy` 和负载均衡中的 `fallbackTag`
例如链式代理中的 `dialerProxy` 和负载均衡中的 `fallbackTag`
- 流量已经分流过一次后,再按更多条件继续细分<br>
比如由同一组路由规则分流后的 TCP 流量和 UDP 要走不同的出站
+2 -2
View File
@@ -98,9 +98,9 @@ Wireguard 服务器列表,其中每一项是一个服务器配置。
当 Wireguard 服务器地址为域名、被代理流量目标地址是域名时,控制它们的域名解析策略。
不像绝大多数代理协议,Wireguard 不允许传递域名作为目标,所以如果传入目标为域名需要解析为 IP 地址后传送,这会经由 Xray 内置DNS处理,此处字段含义见 `Freedom` 出站的 `domainStrategy`,默认值为 `ForceIP`
不像绝大多数代理协议,Wireguard 不允许传递域名作为目标,所以如果传入目标为域名需要解析为 IP 再传送。此处字段含义与 [sockopt.domainStrategy](../transports/sockopt.md#sockoptobject) 中对应的 `Force` 策略相同,默认值为 `ForceIP`
`Freedom` 出站的 `domainStrategy` 包含诸如 `UseIP` 的选项,在这里不提供,因为 Wiregiard 必须获取一个可用的 IP,不能执行 `UseIP` 解析失败后回落为域名的行为。<br>
`sockopt.domainStrategy` 包含诸如 `UseIP` 的选项,在这里不提供,因为 Wireguard 必须获取一个可用的 IP,不能执行 `UseIP` 解析失败后回落为域名的行为。<br>
注意:作用于被代理流量时,此选项还受 `address` 选项的约束,比如你设置了 ForceIPv6v4 但是 address 中没有设置 IPv6 地址,尽管目标域名有 AAAA 记录也不会解析。
### Peers
+33 -36
View File
@@ -97,30 +97,36 @@ Sockopt 用于配置底层网络行为。
默认值 `"AsIs"`
目标地址为域名时,配置相应的值,Outbound 连接远端服务器的行为模式如下
出站需要连接的地址为域名时,此选项控制域名的解析方式
- 当使用 `"AsIs"`, Xray 不对域名进行特殊处理,到最后 Xray 将直接使用 go 自带的 Dial 发起连接,优先级固定为 RFC6724 的默认值(不会遵守 gai.conf 等配置) 通常来说为 IPv6 优先
- 当填写其他值时,将使用 Xray-core [内置 DNS 服务器](../dns.md) 服务器进行解析。若不存在DNSObject,则使用系统DNS。若有多个符合条件的IP地址时,核心会随机选择一个IP作为目标IP。
- 当使用 `"AsIs"`,Xray 将域名交给 Go 按操作系统 DNS 设置解析并连接。通常 TCP 优先尝试 IPv6,并在连接不顺利时尝试 IPv4;UDP 则优先使用 IPv4
::: details AsIs 的地址选择与回退细节
TCP 使用 Go 内置的 Happy Eyeballs。解析结果中第一个地址所属的地址族为首选地址族:若在 300 ms 后仍未连接成功,则开始尝试另一地址族;若首选地址族的全部连接尝试提前失败,则立即尝试另一地址族。这不受 Xray `sockopt.happyEyeballs` 配置控制。参见 [Go 拨号实现](https://go.dev/src/net/dial.go)。
使用纯 Go 编译的 Xray 时,地址按照 RFC 6724 的精简规则排序,条件相当时通常优先 IPv6,不读取 `/etc/gai.conf`。Xray 官方 release 版大多采用这种方式;部分操作系统或下游项目编译的版本行为可能略有不同不再赘述。参见 [Go 地址排序实现](https://go.dev/src/net/addrselect.go)。
UDP 优先选择解析结果中的 IPv4 地址,没有 IPv4 时才选择 IPv6;发送失败不会自动切换到另一地址族。`Use` 策略回退到 `AsIs` 时也遵循此行为。参见 [Go UDP 地址选择实现](https://go.dev/src/net/ipsock.go)。
:::
- 当填写其他值时,将使用 Xray [内置 DNS 模块](../dns.md) 进行解析。若未配置 `DNSObject`,则使用系统 DNS。若有多个符合条件的 IP 地址,默认随机选择一个;TCP 启用 `sockopt.happyEyeballs` 后则通过竞速选择。
- `"IPv4"` 代表只解析 IPv4。`"IPv4v6"` 代表先解析 IPv4,仅当解析报错或没有返回 IP 时再解析 IPv6;如果已经解析出 IPv4,之后连接失败不会回退到 IPv6。`"IPv6"``"IPv6v4"` 同理,地址族顺序相反。
- 当在内置DNS设置了 `"queryStrategy"` 后,实际行为将会与这个选项取并,只有都被包含的IP类型才会被解析,`"queryStrategy": "UseIPv4"` `"domainStrategy": "UseIP"`,实际上等同于 `"domainStrategy": "UseIPv4"`
- 当使用 `"Use"` 开头的选项时,若解析结果不符合要求(如域名只有IPv4解析结果但使用了UseIPv6),则会回落回AsIs。
- 当使用 `"Force"` 开头的选项时,若解析结果不符合要求,则该连接会无法建立。
- 当在内置 DNS 模块中设置了 `"queryStrategy"` 后,实际解析的 IP 类型取两个选项的交集,只有两者都允许的 IP 类型才会被解析。例如`"queryStrategy": "UseIPv4"` 配合 `"domainStrategy": "UseIP"`,实际上等同于 `"domainStrategy": "UseIPv4"`
- 当使用 `"Use"` 开头的选项时,若解析失败或结果不符合要求(如域名只有 IPv4 解析结果但使用了 `UseIPv6`),则会回退到 `AsIs`
- 当使用 `"Force"` 开头的选项时,若解析失败或结果不符合要求,则无法建立连接
::: tip TIP
当使用 `"UseIP"``"ForceIP"` 模式时,并且 [出站连接配置](../outbound.md#outboundobject) 中指定了 `sendThrough` 时,核心会根据 `sendThrough` 的值自动判断所需的 IP 类型,IPv4 或 IPv6。若手动指定了单种IP类型(如UseIPv4),但与 `sendThrough` 指定的本地地址不匹配,将会导致连接失败。
::: tip
当使用 `"UseIP"``"ForceIP"` 模式时,并且 [出站连接配置](../outbound.md#outboundobject) 中指定了 `sendThrough` 时,核心会根据 `sendThrough` 的值自动判断所需的 IP 类型,IPv4 或 IPv6。若手动指定了单种 IP 类型(如 UseIPv4),但与 `sendThrough` 指定的本地地址不匹配,将会导致连接失败。
:::
::: danger
:::: danger 启用了此功能后,不当的配置可能会导致死循环!
连接到服务器,需要等待 DNS 查询结果;完成 DNS 查询,需要连接到服务器。
启用了此功能后,不当的配置可能会导致死循环
**不建议** 经验不足的用户擅自使用此功能
一句话版本:连接到服务器,需要等待 DNS 查询结果;完成 DNS 查询,需要连接到服务器。
::: details 详细解释
> Tony: 先有鸡还是先有蛋?
详细解释:
1. 触发条件:代理服务器(proxy.com)。内置 DNS 服务器,非 Local 模式。
1. 触发条件:代理服务器地址是域名(proxy.com)。内置 DNS 服务器是非 Local 模式。
2. Xray 尝试向 proxy.com 建立 TCP 连接 **前** ,通过内置 DNS 服务器查询 proxy.com。
3. 内置 DNS 服务器向 dns.com 建立连接,并发送查询,以获取 proxy.com 的 IP。
4. **不当的** 的路由规则,导致 proxy.com 代理了步骤 3 中发出的查询。
@@ -136,16 +142,12 @@ Sockopt 用于配置底层网络行为。
- 用 Hosts。
- ~~如果你还是不知道解决方案,就别用这个功能了。~~
因此,**不建议** 经验不足的用户擅自使用此功能。
:::
::::
> `dialerProxy`: ""
一个出站代理的标识。当值不为空时,将使用指定的 outbound 发出连接。可用于支持传输配置链式转发
::: danger
此选项与 ProxySettingsObject.Tag 不兼容
:::
一个出站代理的标识。当值不为空时,将使用指定的 outbound 发出连接。通常用于配置链式代理
> `acceptProxyProtocol`: true | false
@@ -213,23 +215,19 @@ TCP 拥塞控制算法。仅支持 Linux。
默认值 `false`,填写 `true` 时,启用 [Multipath TCP](https://en.wikipedia.org/wiki/Multipath_TCP),仅客户端参数,因为 golang 在 1.24+ 版本已默认在监听时启用 MPTCP.
当前仅支持Linux,需要Linux Kernel 5.6及以上。
> `tcpNoDelay`: true | false
该选项已被删除,因为 golang 默认启用 TCP no delay。 相反地,如果想要禁用,请通过使用 customSockopt 禁用。
> `addressPortStrategy`: "none" | "SrvPortOnly" | "SrvAddressOnly" | "SrvPortAndAddress" | "TxtPortOnly" | "TxtAddressOnly" | "TxtPortAndAddress"
使用 SRV 记录或 TXT 记录指定出站使用的目标地址/端口,默认 `none` 即关闭
使用 SRV 记录或 TXT 记录指定出站使用的目标地址/端口,默认 `none` 即关闭
查询直接通过系统DNS而不是Xray的内置DNS, 尝试去查询的域名将会是出站中的域名。如果查询失败请求会按原地址和端口发出
查询直接通过系统 DNS 而不是 Xray 的内置 DNS, 尝试去查询的域名将会是出站中的域名。如果查询失败请求会按原地址和端口发出
`Srv` 开头代表查询 SRV 记录(标准格式), `Txt` 开头代表查询 TXT 记录(格式形如 `127.0.0.1:80`)
`Srv` 开头代表查询 SRV 记录(标准格式), `Txt` 开头代表查询 TXT 记录 (格式形如 `127.0.0.1:80`)
`PortOnly` 仅重置端口 `AddressOnly` 仅重置地址 `PortAndAddress` 则重置地址和端口
`PortOnly` 仅重置端口 `AddressOnly` 仅重置地址 `PortAndAddress` 则重置地址和端口
该选项生效在 sockopt 里的 domainStrategy 解析之前,地址重置后仍会按 domainStrategy 的规则进行解析(如果有), 但是在 Freedom 的 domainStrategy 之后,如果在其中设置了解析为 IP 则本选项无法生效
该选项在 `sockopt.domainStrategy` 解析之前生效,地址重置后仍会按 `domainStrategy` 的规则进行解析。
PS: 如果有正常上网的域名流量被 AsIs 的 freedom 出站送过来,那么在此设置后会尝试解析并重置地址和端口,比如核心会尝试查询 google.com 的 SRV 记录并按记录重置目标
Freedom 出站不支持此选项
> `customSockopt`: []
@@ -280,13 +278,12 @@ PS: 如果有正常上网的域名流量被 AsIs 的 freedom 出站送过来,
> `happyEyeballs`: [HappyEyeballsObject](#happyeyeballsobject)
RFC-8305 实现的 happyEyeballs,仅适用于 TCP。当目标为域名时对它们竞速并选择第一个成功的返回,仅当 `Sockopt.domainStrategy` 被设置为非 `AsIs` 时生效。
RFC-8305 实现的 happyEyeballs,仅适用于 TCP。当目标为域名时对它们竞速并选择第一个成功的返回,仅当 `sockopt.domainStrategy` 被设置为非 `AsIs` 时生效。
注意:`UseIPv4v6` / `ForceIPv4v6` 会使可用的 IP 列表被缩减到仅剩 IPv4,仅当 IPv4 解析报错或没有返回 IP 时才会改为解析 IPv6;IPv4 连接失败不会触发该回退。不推荐这么用。建议使用 UseIP / ForceIP 配合 `HappyEyeballs.interleave`
注意:`UseIPv4v6` / `ForceIPv4v6` 会使可用的 IP 列表被缩减到仅剩 IPv4,仅当 IPv4 解析报错或没有返回 IP 时才会改为解析 IPv6;IPv4 连接失败不会触发该回退。不推荐这么用。建议使用 UseIP / ForceIP 配合 `happyEyeballs.interleave`
::: warning
使用这个功能时不要使用此出站的 `targetStrategy`,这会导致 `Sockopt` 只能看到被替换完毕的 IP。<br>
此外也不能与 `dialerProxy` 一起使用,这会导致 `happyEyeballs` 无法生效。
不能与 `dialerProxy` 一起使用,否则 `happyEyeballs` 无法生效。
:::
### HappyEyeballsObject
+4 -4
View File
@@ -34,16 +34,16 @@
合理利用 Xray ~~如轮椅般~~强大的内置 DNS 自带的回落、ECS、IP 过滤、打 Tag 等功能,精心调整它们的顺序。如此你便得到了比 geosite cn/!cn 更为精确且实时的 IP 作为分流条件,因为 IP 归属地,特别是 cn 归属地变更频率较低。
在继续阅读本文之前,你需要充分阅读并理解“入门技巧:路由 (routing) 功能简析[上篇](./routing-lv1-part1.md)、[下篇](./routing-lv1-part2.md)”。
与此同时你已经快要把官方配置指南给翻烂了,因此你完全理解了路由和出站中的 domainStrategy、入站中 sniffing 各选项的作用、以及其不同值的组合下产生的行为。
与此同时你已经快要把官方配置指南给翻烂了,因此你完全理解了路由和 sockopt 中的 domainStrategy、出站中的 targetStrategy、入站中 sniffing 各选项的作用、以及其不同值的组合下产生的行为。
一切就绪?请试着理解下面这段内容:
socks、http 入站时,请求的就是域名,到了路由后,路由中非 AsIs 的 domainStrategy 可以利用内置 DNS 解析出 IP 临时用于路由匹配。到了本地 direct 出站时,出站中非 AsIs 的 domainStrategy 可以利用内置 DNS 再次解析出 IP 用于出站。发往 Xray 服务器的请求只有域名,具体访问哪个 IP 取决于服务器的 direct 出站。
socks、http 入站时,原始请求的就是域名,到了路由模块后,路由中非 AsIs 的 domainStrategy 可以利用内置 DNS 解析出 IP 临时用于路由匹配。若分流到了本地 direct 出站sockopt 中非 AsIs 的 domainStrategy 可以利用内置 DNS 再次解析出 IP 用于出站。若分流到了远端 Xray 服务器,并且本地此出站的 targetStrategy 为 AsIs,则请求目标仍以域名形式发送,具体访问哪个 IP 取决于服务器的 direct 出站。
透明代理时情况变得更加复杂,入站 sniffing 开启,且 destOverride 有 [http, tls]
- 若 routeOnly = false 则请求的 IP 将被抹掉,后面的流程跟 socks 入站一样。
- 若 routeOnly = true 则同时有域名和 IP,到了路由后,可以直接匹配域名和 IP 规则,本地 direct 出站也会用此 IP。发往 Xray 服务器的请求只有 IP,服务器如何处理?再把刚才的流程走一遍。
- 若 routeOnly = true 则同时有域名和 IP,到了路由模块后,可以直接匹配域名和 IP 规则,本地 direct 出站也会用此 IP。发往 Xray 服务器的请求只有 IP,服务器如何处理?再把刚才的流程走一遍。
遇到困难?你需要继续反复阅读官方指南并尝试理解。否则你很难利用到下面示例中 DNS 模块的解析结果来正确分流。
@@ -261,7 +261,7 @@ realIp 透明代理环境,你甚至可以在保证完全劫持各种渠道的
此场景下由于发给 Xray 服务器的请求全部都是域名,因此没有必要利用 DNS 反复试探最优结果,只需要快速识别域是否被污染,尽可能解析出中国的 CDN 友好的 IP 即可。
此示例中 DNS 模块解析出的中国 IP 已经是 99% 中国 CDN 友好的,因此你可以 direct 出站 `domainStrategy` 设为**非** AsIs 以利用缓存,如果你需要的话;<br>
此示例中 DNS 模块解析出的中国 IP 已经是 99% 中国 CDN 友好的,因此你可以 direct 出站 `sockopt.domainStrategy` 设为**非** AsIs 以利用缓存,如果你需要的话;<br>
如果你追求 100% 的中国 CDN 友好,可设为 AsIs 利用操作系统设置的 DNS 再解析一次,额外耗时约 1 ~ 数百毫秒,建议开启乐观缓存以进一步降低延迟。
## 写在后面
+13 -13
View File
@@ -114,8 +114,10 @@ lsmod | grep wireguard
"outbounds": [
{
"protocol": "freedom",
"settings": {
"domainStrategy": "UseIPv4"
"streamSettings": {
"sockopt": {
"domainStrategy": "UseIPv4"
}
}
//修改此处,可v4或者v6
},
@@ -125,11 +127,9 @@ lsmod | grep wireguard
"tag": "wg0",
"streamSettings": {
"sockopt": {
"mark": 255 // <mark>
"mark": 255, // <mark>
"domainStrategy": "UseIPv6"
}
},
"settings": {
"domainStrategy": "UseIPv6"
}
}, //设置fwmark为<mark>的用户走指定方式”UseIPv6””UseIPv4”
// <--请在不同的方案中选择--> 方案2sendThrough
@@ -138,8 +138,10 @@ lsmod | grep wireguard
"protocol": "freedom",
"sendThrough": "your wg0 v4 address",
//修改此处,可v4或者v6
"settings": {
"domainStrategy": "UseIPv4"
"streamSettings": {
"sockopt": {
"domainStrategy": "UseIPv4"
}
}
//修改此处,可v4或者v6
},
@@ -147,12 +149,10 @@ lsmod | grep wireguard
{
"tag": "wg0",
"protocol": "freedom",
"settings": {
"domainStrategy": "UseIPv4"
},
"streamSettings": {
"sockopt": {
"interface": "wg0"
"interface": "wg0",
"domainStrategy": "UseIPv4"
}
}
},
@@ -193,7 +193,7 @@ lsmod | grep wireguard
```
::: tip
可以通过修改 "domainStrategy": "UseIPv6"来控制对应用户的访问方式 实测优先级要高于系统本身的 gai.config
可以通过修改 `sockopt.domainStrategy``UseIPv6` 来控制对应用户的访问方式
:::
## 5、系统设置配置
+4 -8
View File
@@ -52,12 +52,10 @@ sudo curl -oL /usr/local/share/xray/geosite.dat https://github.com/Loyalsoldier/
{
"tag": "direct",
"protocol": "freedom",
"settings": {
"domainStrategy": "UseIPv4"
},
"streamSettings": {
"sockopt": {
"mark": 2
"mark": 2,
"domainStrategy": "UseIPv4"
}
}
},
@@ -94,12 +92,10 @@ sudo curl -oL /usr/local/share/xray/geosite.dat https://github.com/Loyalsoldier/
"settings": {
"rewriteAddress": "8.8.8.8"
},
"proxySettings": {
"tag": "proxy"
},
"streamSettings": {
"sockopt": {
"mark": 2
"mark": 2,
"dialerProxy": "proxy"
}
}
}
@@ -91,12 +91,10 @@
{
"tag": "direct",
"protocol": "freedom",
"settings": {
"domainStrategy": "UseIP"
},
"streamSettings": {
"sockopt": {
"mark": 255
"mark": 255,
"domainStrategy": "UseIP"
}
}
},
+16 -16
View File
@@ -4,23 +4,19 @@
The built-in DNS module in Xray has three main purposes:
- **Routing Phase:** Resolves domain names to IPs and matches rules based on the resolved IPs for traffic splitting. Whether to resolve the domain and split traffic depends on the `domainStrategy` setting in the routing configuration module. The built-in DNS server is used for DNS queries only when the following two values are set:
- `"IPIfNonMatch"`: When a domain is requested, Xray attempts to match it against the `domain` rules in the routing configuration. If no match is found, the built-in DNS server is used to resolve the domain, and the returned IP address is used to match against IP routing rules.
- `"IPOnDemand"`: When any IP-based rule is encountered during matching, the domain is immediately resolved to an IP for matching.
- **Routing Phase:** Resolves domain names to IPs and matches rules based on the resolved IPs for traffic splitting.<br>
Whether a domain is resolved for routing depends on `routing.domainStrategy`. The built-in DNS server is used for DNS queries only with the following values:
- `"IPIfNonMatch"`: When the request target is a domain name without an accompanying IP, Xray first performs a round of matching using the other conditions. If no routing rule matches in that round, it resolves the domain through the built-in DNS server and performs another round of routing rule matching using the returned IP addresses.
- `"IPOnDemand"`: When the request target is a domain name without an accompanying IP, the domain is immediately resolved to IPs for matching as soon as routing encounters an IP-based rule.
- **Resolving Target Addresses for Connections:**
- For example, in a `freedom` outbound, if `domainStrategy` is set to `UseIP`, requests sent from this outbound will first resolve the domain to an IP using the built-in server before connecting.
- For example, in `sockopt`, if `domainStrategy` is set to `UseIP`, system connections initiated by this outbound will first resolve to an IP using the built-in server before connecting.
- **Outbound Phase:** Resolves target domain names for connections or for sending to a remote proxy server:
- For example, setting `targetStrategy` to `UseIP` in a VLESS outbound resolves the target domain of the proxied request through the local built-in DNS module, then sends the resolved IP to the remote proxy server.
- Setting `sockopt.domainStrategy` to `UseIP` in a VLESS outbound resolves the VLESS server's domain through the built-in DNS module, then connects to the resolved IP.
- Setting `sockopt.domainStrategy` to `UseIP` in a Freedom outbound resolves the request's target domain through the built-in DNS module, then connects to the resolved IP.
- WireGuard does not allow domain names as destinations, so its outbound can use the built-in DNS module to resolve them to IPs.
- **TUN/Transparent Proxy DNS Traffic Hijacking:** Combines routing with the DNS outbound to hijack DNS traffic into this module; or directly exposes port 53 to act as a recursive DNS server.
::: tip TIP 1
The DNS server enters the routing system for matching by default unless it contains `+local`. When using domain names within it, be aware of potential routing loops; `hosts` may help.
:::
::: tip TIP 2
Only basic IP queries (A and AAAA records) are supported. CNAME records will be queried repeatedly until an A/AAAA record is returned. Other queries will not enter the built-in DNS server; instead, they may be discarded or transparently forwarded to other servers depending on your outbound configuration.
:::
- **TUN/Transparent Proxy DNS Traffic Hijacking:** Combines routing with the DNS outbound to hijack DNS traffic into this module; or uses [Tunnel](./inbounds/tunnel.md) to expose port 53 and act as a recursive DNS server.
- Only basic IP queries (A and AAAA records) are supported. CNAME records will be queried repeatedly until an A/AAAA record is returned. Other queries will not enter the built-in DNS server; instead, they may be discarded or transparently forwarded to other servers depending on your outbound configuration.
## DNS Processing Flow
@@ -136,6 +132,10 @@ The DNS clients initialized by different rules will be shown in the Xray startup
(v1.4.0+) You can enable DNS query logging in [Log](./log.md).
:::
::: tip TIP 4
The DNS server enters the routing system for matching by default unless it contains `+local`. When using domain names within it, be aware of potential routing loops; `hosts` may help.
:::
> `clientIp`: string
The IP address used in the EDNS Client Subnet extension.
@@ -297,7 +297,7 @@ There are two scenarios for DNS requests sent by the DNS module:
**Local Mode** connections are made directly outwards by the core. In this case, if the address is a domain name, it will be resolved by the system itself. The logic is relatively simple.
**Non-Local** modes will essentially be treated as requests coming from an inbound with the tag `dns.tag` (Don't know where it is? Ctrl+F in your browser to search for `inboundTag`). They will go through the normal core processing flow and may be assigned by the routing module to a local freedom or other remote outbounds. They will be resolved by the freedom's `domainStrategy` (beware of potential loops) or sent directly as domains to the remote end to be resolved according to the server's own resolution method.
**Non-Local Mode:** DNS queries enter the routing system as internal requests, with their `inboundTag` specified by `tag` in the DNS configuration. If a request is routed to a local Freedom outbound, the DNS server's own domain name is resolved according to that outbound's `sockopt.domainStrategy` (beware of potential loops). If it is routed to a remote proxy outbound, the domain name can be passed to the remote end for resolution.
Since it might be difficult for average users to clarify the logic involved, it is recommended (especially in a transparent proxy environment) to **directly set the corresponding IPs for servers with domain names in the host option of the DNS module** to prevent loops.
+4 -34
View File
@@ -19,10 +19,6 @@ The first element in the list serves as the primary outbound. When a routing mat
"settings": {},
"tag": "identifier",
"streamSettings": {},
"proxySettings": {
"tag": "another-outbound-tag",
"transportLayer": false
},
"mux": {},
"targetStrategy": "AsIs"
}
@@ -67,48 +63,22 @@ When not empty, its value must be **unique** among all `tag`s.
Transport configuration for this outbound.
> `proxySettings`: [ProxySettingsObject](#proxysettingsobject)
Outbound proxy configuration.
> `mux`: [MuxObject](#muxobject)
Specific configuration related to Mux.
> `targetStrategy`: "AsIs" | "UseIP" | "UseIPv6v4" | "UseIPv6" | "UseIPv4v6" | "UseIPv4" | "ForceIP" | "ForceIPv6v4" | "ForceIPv6" | "ForceIPv4v6" | "ForceIPv4"
If this outbound attempts to send a domain request, this controls whether it is resolved/how it is resolved to an IP before sending.
Applies to outbounds other than Freedom. Controls whether the target domain name in a proxied request is resolved locally to an IP and which resolution strategy is used.
The default value is `AsIs`, meaning it is sent to the remote server as is. All parameter meanings are roughly equivalent to `domainStrategy` in [Sockopt](./transports/sockopt.md#sockoptobject).
The default value is `AsIs`, which sends the target domain name unchanged to the remote server. The strategies have essentially the same meanings as `domainStrategy` in [Sockopt](./transports/sockopt.md#sockoptobject).
::: tip
This controls **proxied requests**. If the address of the outbound proxy server is a domain name, and you need to select a resolution strategy for the domain name itself, you should configure `domainStrategy` in [Sockopt](./transports/sockopt.md#sockoptobject).
Freedom's domain resolution strategy should also be configured through `sockopt.domainStrategy`.
:::
### ProxySettingsObject
```json
{
"tag": "another-outbound-tag",
"transportLayer": false
}
```
> `tag`: string
When the identifier of another outbound is specified, data sent by this outbound will be forwarded to the specified outbound for transmission.
::: danger
This option conflicts with [Sockopt.dialerProxy](./transports/sockopt.md#sockoptobject). Choose one as needed.
By default, this forwarding method **ignores** this outbound's own transport configuration (such as XHTTP, REALITY, or Sockopt), meaning the `streamSettings` of this outbound will not take effect.<br>
If you need forwarding that works together with `streamSettings`, please use `Sockopt.dialerProxy` instead or set `transportLayer` to `true` here.
:::
> `transportLayer`: true | false
`true` converts this setting to `Sockopt.dialerProxy` so the forwarding can use this outbound's `streamSettings`. The default is `false`.
### MuxObject
The Mux function distributes data from multiple TCP connections over a single TCP connection. For implementation details, see [Mux.Cool](../development/protocols/muxcool.md). Mux is designed to reduce TCP handshake latency, not to increase connection throughput. Using Mux for watching videos, downloading, or speed testing usually has a negative effect. Mux only needs to be enabled on the client side; the server side adapts automatically. The second use of Mux is to distribute multiple UDP connections, i.e., XUDP.
+73 -44
View File
@@ -1,6 +1,6 @@
# Freedom (fragment, noises)
Freedom is an outbound protocol used to send (normal) TCP or UDP data to any network.
Freedom is a direct outbound protocol and usually the final endpoint for traffic: it receives TCP or UDP traffic from upstream, connects directly to the final destination, and sends and receives data.
::: warning
This outbound has a default safety policy in server-side and reverse-proxy scenarios, which may block some targets. See `finalRules` below for how to allow them.
@@ -16,9 +16,8 @@ This outbound has a default safety policy in server-side and reverse-proxy scena
{
// ...
"protocol": "freedom",
// [!code focus:29]
// [!code focus:28]
"settings": {
"domainStrategy": "AsIs",
"redirect": "127.0.0.1:3366",
"userLevel": 0,
"fragment": {
@@ -51,21 +50,13 @@ This outbound has a default safety policy in server-side and reverse-proxy scena
}
```
> `domainStrategy`: "AsIs"<br>
> "UseIP" | "UseIPv6v4" | "UseIPv6" | "UseIPv4v6" | "UseIPv4"<br>
> "ForceIP" | "ForceIPv6v4" | "ForceIPv6" | "ForceIPv4v6" | "ForceIPv4"
Default value `"AsIs"`.
The meanings of all parameters are roughly equivalent to `domainStrategy` in [Sockopt](../transports/sockopt.md#sockoptobject).
Only using `"AsIs"` here allows passing the domain name to the subsequent `sockopt` module. If set to non-`"AsIs"` here, causing the domain to be resolved to a specific IP, it will invalidate the subsequent `sockopt.domainStrategy` and its related `happyEyeballs`. (There is no negative impact if these two settings are not adjusted).
When sending UDP, Freedom ignores `domainStrategy` in `sockopt` for some reasons and forcibly prefers IPv4 by default.
::: tip
Freedom's target domain resolution strategy is controlled by [sockopt.domainStrategy](../transports/sockopt.md#sockoptobject).
:::
> `redirect`: address_port
Freedom will forcibly send all data to the specified address (instead of the address specified by the inbound).
Freedom rewrites the connection's current destination address and port to those specified in `redirect`.
The value is a string, e.g., `"127.0.0.1:80"`, `":1234"`.
@@ -78,36 +69,15 @@ User level. Connections will use the [Local Policy](../policy.md#levelpolicyobje
The value of `userLevel` corresponds to the value of `level` in [policy](../policy.md#policyobject). If not specified, it defaults to 0.
> `fragment`: map
> `fragment`: [FragmentObject](#fragmentobject)
A set of key-value configuration items used to control outgoing TCP fragmentation. In some cases, it can deceive censorship systems, such as bypassing SNI blacklists.
`"length"` and `"interval"` are both [Int32Range](../../development/intro/guide.md#int32range) types.
`"packets"`: Supports two fragmentation modes. `"1-3"` is TCP stream slicing, applied to the 1st through 3rd data writes by the client. `"tlshello"` is TLS handshake packet slicing.
`"length"`: Fragment packet length (byte).
`"interval"`: Fragment interval (ms).
When `interval` is 0 and `"packets": "tlshello"` is set, the fragmented Client Hello will be sent in one TCP packet (provided its original size does not exceed MSS or MTU causing automatic system fragmentation).
> `noises`: array
> `noises`: \[ [NoiseObject](#noiseobject) \]
UDP noise, used to send some random data as "noise" before sending a UDP connection. Presence of this structure implies enablement. It might deceive sniffers, or it might disrupt normal connections. _Use at your own risk._ For this reason, it bypasses port 53 because that breaks DNS.
It is an array where multiple noise packets to be sent can be defined. A single element in the array is defined as follows:
`"type"`: Noise packet type. Currently supports `"rand"` (random data), `"str"` (user-defined string), `"base64"` (base64 encoded custom binary data).
`"packet"`: The content of the packet to be sent based on the preceding `type`.
- When `type` is `rand`, this specifies the length of the random data. It can be a fixed value `"100"` or a floating range `"50-150"`.
- When `type` is `str`, this specifies the string to be sent.
- When `type` is `hex`, this specifies binary data in hex format.
- When `type` is `base64`, this specifies base64 encoded binary data.
`"delay"`: Delay in milliseconds. After sending this noise packet, the core will wait for this time before sending the next noise packet or real data. Defaults to no wait. It is an [Int32Range](../../development/intro/guide.md#int32range) type.
An array that can define multiple noise packets to send. Each element is a [NoiseObject](#noiseobject).
> `proxyProtocol`: number
@@ -115,13 +85,23 @@ PROXY protocol is usually used with `redirect` to redirect traffic to Nginx or o
The value of `proxyProtocol` is the PROXY protocol version number. Options are `1` or `2`. If not specified, it defaults to `0` (disabled).
> `finalRules`: \[[FinalRuleObject](#finalruleobject)\]
> `finalRules`: \[ [FinalRuleObject](#finalruleobject) \]
Matches Freedom final outbound rules in order, and allows or blocks connection targets.
Compared with blocking in `routing`, `finalRules` applies at Freedom's final outbound stage: matching happens after the final IP is resolved and before dialing; in addition, UDP is also matched packet by packet during send and receive, making it stricter and more thorough. Each rule match takes about 50-150 ns.
Compared with blocking in `routing`, `finalRules` applies at Freedom's final outbound stage, both before and after dialing. UDP is also checked packet by packet during send and receive, making enforcement stricter and more thorough. Each rule match takes about 50-150 ns, so performance is not a concern.
Note: whenever Freedom needs to apply `finalRules`, if `domainStrategy` is `AsIs` and the target is a domain, Freedom still resolves the target to an IP through the operating system DNS before matching rules. At that point the target is no longer a domain, so the later `sockopt.domainStrategy` and its `happyEyeballs` no longer take effect.
::: details When the target is a domain name
When the target is a domain name and rules need to be applied, Freedom resolves it according to `sockopt.domainStrategy` before dialing, then checks every returned IP against the rules in order. If any IP is blocked, the entire request is blocked.
After dialing succeeds, Freedom checks the actual remote IP of the connection against the rules again. Therefore, if resolution before dialing fails or the two resolutions return different results, TCP handshake packets may still be sent before the connection enters the blackhole state.
Each UDP packet addressed to a domain name also triggers domain resolution when sent. However, the per-packet check only matches the destination IP selected for that packet against the rules in order to decide whether to block it; it does not check every IP returned by resolution.
:::
::: tip
If `sockopt.dialerProxy` is configured for this outbound, Freedom is no longer the final outbound, so it does not apply `finalRules` or the default safety policy described below.
:::
::: warning
There is a default fallback safety policy for server-side and reverse-proxy scenarios:
@@ -129,10 +109,59 @@ There is a default fallback safety policy for server-side and reverse-proxy scen
If no explicit rule matches, the built-in fallback rule is used: traffic from the VLESS reverse proxy blocks all targets by default; traffic from `VLESS`, `VMess`, `Trojan`, `Shadowsocks`, `Hysteria`, or `WireGuard` inbounds blocks private and reserved IP ranges by default; other traffic is fully allowed by default.
If the server needs to allow clients to access some internal services, explicitly configure `allow` rules and limit them to the necessary `network`, `ip`, and `port` whenever possible.
If the server also needs features that rely on passing the domain to `sockopt` (such as `sockopt.domainStrategy` or `happyEyeballs`), it cannot continue relying on this default safety policy. You can configure the first rule as an `allow` rule without any matching conditions to restore the previous behavior; this is also equivalent to disabling this default safety policy, so evaluate the security impact yourself.
:::
### FragmentObject
```json
{
"packets": "tlshello",
"length": "100-200",
"interval": "10-20"
}
```
> `packets`: string
Supports two fragmentation modes. `"1-3"` is TCP stream slicing, applied to the 1st through 3rd data writes by the client. `"tlshello"` is TLS handshake packet slicing.
> `length`: [Int32Range](../../development/intro/guide.md#int32range)
Fragment packet length (bytes).
> `interval`: [Int32Range](../../development/intro/guide.md#int32range)
Fragment interval (ms).
When `interval` is 0 and `"packets": "tlshello"` is set, the fragmented Client Hello will be sent in one TCP packet (provided its original size does not exceed MSS or MTU causing automatic system fragmentation).
### NoiseObject
```json
{
"type": "base64",
"packet": "7nQBAAABAAAAAAAABnQtcmluZwZtc2VkZ2UDbmV0AAABAAE=",
"delay": "10-16"
}
```
> `type`: string
Noise packet type. Currently supports `"rand"` (random data), `"str"` (user-defined string), and `"base64"` (base64-encoded custom binary data).
> `packet`: string
The content of the packet to be sent based on the preceding `type`.
- When `type` is `rand`, this specifies the length of the random data. It can be a fixed value `"100"` or a range `"50-150"`.
- When `type` is `str`, this specifies the string to be sent.
- When `type` is `hex`, this specifies binary data in hex format.
- When `type` is `base64`, this specifies base64-encoded binary data.
> `delay`: [Int32Range](../../development/intro/guide.md#int32range)
Delay in milliseconds. After sending this noise packet, the core waits for this duration before sending the next noise packet or real data. Defaults to no wait.
### FinalRuleObject
```json
+1 -1
View File
@@ -5,7 +5,7 @@ Loopback is a loopback outbound used to send traffic back to routing for further
::: tip Uses
- In places where only an outbound can be specified and `balancerTag` cannot be written directly, Loopback can be used to indirectly use a balancer.<br>
For example, `proxySettings` and `dialerProxy` in chained proxies, and `fallbackTag` in load balancing.
For example, `dialerProxy` in chained proxies, and `fallbackTag` in load balancing.
- After traffic has already been routed once, it can be further subdivided based on more conditions.<br>
For example, TCP traffic and UDP traffic routed by the same set of routing rules can be sent to different outbounds.
+2 -2
View File
@@ -98,9 +98,9 @@ List of Wireguard servers, where each item is a server configuration.
Controls the domain resolution strategy when the Wireguard server address is a domain name or the target address of the proxied traffic is a domain name.
Unlike most proxy protocols, Wireguard does not allow passing domain names as targets. Therefore, if the incoming target is a domain, it needs to be resolved to an IP address before transmission. This is handled by Xray's built-in DNS. The meaning of this field is the same as `domainStrategy` in `Freedom` outbound. The default value is `ForceIP`.
Unlike most proxy protocols, Wireguard does not allow passing domain names as targets. Therefore, if the incoming target is a domain name, it must be resolved to an IP before transmission. The meanings of this field match the corresponding `Force` strategies in [sockopt.domainStrategy](../transports/sockopt.md#sockoptobject). The default value is `ForceIP`.
The `domainStrategy` of `Freedom` outbound includes options like `UseIP`, which are not provided here because Wireguard must obtain a usable IP and cannot perform the behavior of falling back to a domain name after `UseIP` resolution fails.<br>
`sockopt.domainStrategy` includes options like `UseIP`, which are not provided here because Wireguard must obtain a usable IP and cannot perform the behavior of falling back to a domain name after `UseIP` resolution fails.<br>
Note: When applied to proxied traffic, this option is also constrained by the `address` option. For example, if you set `ForceIPv6v4` but no IPv6 address is set in `address`, even if the target domain has AAAA records, they will not be resolved/used.
### Peers
+28 -30
View File
@@ -93,29 +93,36 @@ When [tunnel](../inbounds/tunnel.md) has `followRedirect` set to `true`, and `tp
The default value is `"AsIs"`.
When the target address is a domain name, this field controls how outbound connections resolve and use that target:
When the address an outbound needs to connect to is a domain name, this option controls how it is resolved:
- With `"AsIs"`, Xray does not specially handle the domain name. In the end it uses Go's built-in dialer directly. The priority is fixed to the RFC 6724 default and does not follow configurations such as `gai.conf`, so in practice IPv6 is usually preferred.
- With any other value, Xray uses the Xray-core [built-in DNS server](../dns.md) for resolution. If there is no `DNSObject`, system DNS is used. If multiple IP addresses match, the core randomly picks one target IP.
- With `"AsIs"`, Xray passes the domain name to Go, which resolves it using the operating system's DNS settings and connects. TCP usually tries IPv6 first and tries IPv4 if the connection does not proceed smoothly; UDP prefers IPv4.
::: details Address selection and fallback with AsIs
TCP uses Go's built-in Happy Eyeballs. The address family of the first resolved address is preferred. If the connection has not succeeded after 300 ms, attempts with the other address family begin. If all attempts with the preferred family fail sooner, the other family is tried immediately. This is not controlled by Xray's `sockopt.happyEyeballs`. See [Go's dialing implementation](https://go.dev/src/net/dial.go).
With a pure Go build of Xray, addresses are sorted using a simplified version of RFC 6724, which usually prefers IPv6 when other conditions are equal and does not read `/etc/gai.conf`. Most official Xray release builds use this approach; behavior may differ slightly on some operating systems or in downstream builds. See [Go's address sorting implementation](https://go.dev/src/net/addrselect.go).
UDP prefers an IPv4 address from the resolved results and uses IPv6 only if no IPv4 address is available. A send failure does not automatically switch to the other address family. This also applies when a `Use` strategy falls back to `AsIs`. See [Go's UDP address selection implementation](https://go.dev/src/net/ipsock.go).
:::
- With any other value, Xray uses its [built-in DNS module](../dns.md) for resolution. If no `DNSObject` is configured, system DNS is used. If multiple IP addresses match, one is selected randomly by default; when `sockopt.happyEyeballs` is enabled for TCP, the addresses are raced instead.
- `"IPv4"` means resolve IPv4 only. `"IPv4v6"` means resolve IPv4 first and resolve IPv6 only if that lookup returns an error or no IP addresses. If IPv4 addresses are resolved but subsequent connection attempts fail, it does not fall back to IPv6. `"IPv6"` and `"IPv6v4"` work analogously, with the address-family order reversed.
- When built-in DNS also sets `"queryStrategy"`, the actual behavior is the intersection of the two settings. Only IP types included in both are resolved. For example, `"queryStrategy": "UseIPv4"` together with `"domainStrategy": "UseIP"` behaves the same as `"domainStrategy": "UseIPv4"`.
- When using a `"Use"` option, Xray falls back to `"AsIs"` if the resolution result does not match the requested family, such as a domain that only has IPv4 while using `UseIPv6`.
- When using a `"Force"` option, the connection fails outright if the resolution result does not match the requested family.
- When the built-in DNS module also sets `"queryStrategy"`, the resolved IP types are the intersection of the two settings: only IP types allowed by both are resolved. For example, `"queryStrategy": "UseIPv4"` together with `"domainStrategy": "UseIP"` behaves the same as `"domainStrategy": "UseIPv4"`.
- With a `"Use"` option, Xray falls back to `AsIs` if resolution fails or the results do not meet the requirements, such as a domain that only resolves to IPv4 while `UseIPv6` is selected.
- With a `"Force"` option, the connection cannot be established if resolution fails or the results do not meet the requirements.
::: tip TIP
::: tip
When using `"UseIP"` or `"ForceIP"`, and [OutboundObject](../outbound.md#outboundobject) specifies `sendThrough`, the core automatically infers whether IPv4 or IPv6 is needed from the local address. If you manually force a single IP family, such as `UseIPv4`, but it conflicts with `sendThrough`, the connection fails.
:::
::: danger
Improper use of this feature can create an infinite loop.
:::: danger Improper configuration of this feature can create an infinite loop!
Connecting to the server needs a DNS result, but completing the DNS query also needs to connect to the server.
Short version: connecting to the server needs a DNS result, but completing the DNS query also needs to connect to the server.
This feature is **not recommended** for inexperienced users unless they understand the routing implications.
> Tony: which came first, the chicken or the egg?
::: details Detailed explanation
Detailed explanation:
1. Trigger condition: the proxy server is `proxy.com`, and the built-in DNS server is enabled in non-Local mode.
1. Trigger condition: the proxy server address is a domain name (`proxy.com`), and the built-in DNS server is in non-Local mode.
2. Before Xray establishes a TCP connection to `proxy.com`, it queries `proxy.com` through the built-in DNS server.
3. The built-in DNS server connects to `dns.com` and sends a query to obtain the IP of `proxy.com`.
4. Bad routing rules cause the request sent in step 3 to be proxied through `proxy.com`.
@@ -131,16 +138,12 @@ Possible solutions:
- Use hosts.
- ~~If you still do not know how to solve it, do not use this feature.~~
So this feature is **not recommended** for inexperienced users unless they understand the routing implications.
:::
::::
> `dialerProxy`: ""
An outbound identifier. When non-empty, the specified outbound is used to establish the connection. It can be used for chained forwarding that still respects transport configuration.
::: danger
This option is incompatible with `ProxySettingsObject.Tag`.
:::
An outbound identifier. When non-empty, the specified outbound is used to establish the connection. This is commonly used to configure chained proxies.
> `acceptProxyProtocol`: true | false
@@ -207,10 +210,6 @@ Bind the advertised TCP window size to this value. The kernel chooses the larger
The default value is `false`. When set to `true`, [Multipath TCP](https://en.wikipedia.org/wiki/Multipath_TCP) is enabled. This is client-only, because starting with Go 1.24 MPTCP is enabled by default when listening. It currently requires Linux kernel 5.6 or later.
> `tcpNoDelay`: true | false
This field has been removed because Go enables TCP no delay by default. If you want to disable it, do so through `customSockopt`.
> `addressPortStrategy`: "none" | "SrvPortOnly" | "SrvAddressOnly" | "SrvPortAndAddress" | "TxtPortOnly" | "TxtAddressOnly" | "TxtPortAndAddress"
Use SRV records or TXT records to specify the target address and or port used by outbound. The default value is `none`, which disables the feature.
@@ -221,9 +220,9 @@ These lookups go through system DNS rather than Xray's built-in DNS. The queried
`PortOnly` resets only the port. `AddressOnly` resets only the address. `PortAndAddress` resets both.
This option takes effect before `domainStrategy` inside `sockopt`. After the address is rewritten, it is still resolved according to `domainStrategy`, if any. However, it takes effect after `Freedom`'s own `domainStrategy`, so if that one already resolved the domain to an IP, this option no longer works.
This option takes effect before `sockopt.domainStrategy` resolves the address. After the address is rewritten, it is still resolved according to `domainStrategy`.
As a practical consequence, if ordinary domain traffic is sent into a `Freedom` outbound with `AsIs`, enabling this field makes the core try to resolve and rewrite the address and port, for example by querying `google.com` for SRV records.
Freedom outbounds do not support this option.
> `customSockopt`: []
@@ -274,13 +273,12 @@ When `type` is `int`, the value must be a decimal number.
> `happyEyeballs`: [HappyEyeballsObject](#happyeyeballsobject)
An RFC 8305 Happy Eyeballs implementation, TCP only. When the target is a domain name, it races the resolved addresses and chooses the first successful one. It only works when `Sockopt.domainStrategy` is not `AsIs`.
An RFC 8305 Happy Eyeballs implementation, TCP only. When the target is a domain name, it races the resolved addresses and chooses the first successful one. It only works when `sockopt.domainStrategy` is not `AsIs`.
Note that `UseIPv4v6` and `ForceIPv4v6` effectively reduce the usable IP list to IPv4 and switch to resolving IPv6 only if IPv4 resolution returns an error or no IP addresses. Failure to connect over IPv4 does not trigger this fallback. This usage is not recommended. Prefer `UseIP` or `ForceIP` together with `HappyEyeballs.interleave`.
Note that `UseIPv4v6` and `ForceIPv4v6` effectively reduce the usable IP list to IPv4 and switch to resolving IPv6 only if IPv4 resolution returns an error or no IP addresses. Failure to connect over IPv4 does not trigger this fallback. This usage is not recommended. Prefer `UseIP` or `ForceIP` together with `happyEyeballs.interleave`.
::: warning
Do not use this feature together with this outbound's `targetStrategy`, because then `Sockopt` only sees the final IP after replacement.<br>
Do not use it together with `dialerProxy` either, because that prevents `happyEyeballs` from taking effect.
Do not use this feature together with `dialerProxy`, because that prevents `happyEyeballs` from taking effect.
:::
### HappyEyeballsObject
+3 -3
View File
@@ -34,11 +34,11 @@ The answer is: **Absolutely.**
By making reasonable use of Xray's ~~wheelchair-like~~ powerful built-in DNS features—such as Fallbacks, ECS (EDNS Client Subnet), IP filtering, and Tagging—and carefully adjusting their order, you can obtain a much more accurate and real-time routing condition than `geosite cn/!cn`: the IP address. This works because IP geolocation, especially CN geolocation, changes much less frequently than domain lists.
Before reading further, you need to fully read and understand the "Beginner Skills: Analysis of the Routing Feature [Part 1](./routing-lv1-part1.md) & [Part 2](./routing-lv1-part2.md)".
At the same time, you should have practically memorized the official configuration guide. You must fully understand the functions of `domainStrategy` in routing/outbounds, `sniffing` options in inbounds, and the behaviors produced by their different combinations.
At the same time, you should have practically memorized the official configuration guide. You must fully understand the functions of `domainStrategy` in routing and `sockopt`, `targetStrategy` in outbounds, `sniffing` options in inbounds, and the behaviors produced by their different combinations.
Ready? Please try to understand the following paragraph:
When using **socks/http inbounds**, the request is a domain name. When it reaches the **Routing** module, a `domainStrategy` other than `AsIs` can use the built-in DNS to resolve an IP specifically for routing matching. When the traffic reaches a local **direct outbound**, a `domainStrategy` other than `AsIs` in the outbound can use the built-in DNS to resolve the IP again for the actual connection. The request sent to the Xray Server (remote) contains only the domain name; which IP is actually accessed depends on the server's direct outbound.
When using **socks/http inbounds**, the original request targets a domain name. When it reaches the **Routing** module, a `domainStrategy` other than `AsIs` can use the built-in DNS to resolve IPs temporarily for routing rule matching. If the traffic is routed to a local **direct outbound**, a `domainStrategy` other than `AsIs` in `sockopt` can use the built-in DNS to resolve IPs again for the outbound connection. If the traffic is routed to a remote Xray server and `targetStrategy` on the local outbound is `AsIs`, the request target is still sent as a domain name; which IP is actually accessed depends on the server's direct outbound.
The situation becomes more complex with **Transparent Proxy**. If inbound `sniffing` is enabled and `destOverride` includes `[http, tls]`:
@@ -262,7 +262,7 @@ In a realIp transparent proxy environment, you can even ensure that after hijack
In this scenario, since all requests sent to the Xray Server are domain names, there is no need to use DNS to repeatedly probe for the optimal result. We only need to quickly identify if the domain is polluted and resolve a Chinese CDN-friendly IP as much as possible.
The China IP resolved by the DNS module in this example is already 99% China CDN friendly. Therefore, you can set `domainStrategy` in the direct outbound to **non-AsIs** to utilize the cache if you wish.
The China IP resolved by the DNS module in this example is already 99% China CDN friendly. Therefore, you can set `sockopt.domainStrategy` in the direct outbound to **non-AsIs** to utilize the cache if you wish.
<br>
If you pursue 100% China CDN friendliness, you can set it to `AsIs` to use the OS configured DNS to resolve it again. This adds about 1ms to hundreds of ms of latency; it is recommended to enable optimistic caching to further reduce latency.
+13 -13
View File
@@ -113,8 +113,10 @@ lsmod | grep wireguard
"outbounds": [
{
"protocol": "freedom",
"settings": {
"domainStrategy": "UseIPv4"
"streamSettings": {
"sockopt": {
"domainStrategy": "UseIPv4"
}
}
// Modify here, can be v4 or v6
},
@@ -124,11 +126,9 @@ lsmod | grep wireguard
"tag": "wg0",
"streamSettings": {
"sockopt": {
"mark": 255 // <mark>
"mark": 255, // <mark>
"domainStrategy": "UseIPv6"
}
},
"settings": {
"domainStrategy": "UseIPv6"
}
}, // Users with fwmark set to <mark> use the specified strategy "UseIPv6" or "UseIPv4"
// <--Please choose between different schemes--> Scheme 2: sendThrough
@@ -137,8 +137,10 @@ lsmod | grep wireguard
"protocol": "freedom",
"sendThrough": "your wg0 v4 address",
// Modify here, can be v4 or v6
"settings": {
"domainStrategy": "UseIPv4"
"streamSettings": {
"sockopt": {
"domainStrategy": "UseIPv4"
}
}
// Modify here, can be v4 or v6
},
@@ -146,12 +148,10 @@ lsmod | grep wireguard
{
"tag": "wg0",
"protocol": "freedom",
"settings": {
"domainStrategy": "UseIPv4"
},
"streamSettings": {
"sockopt": {
"interface": "wg0"
"interface": "wg0",
"domainStrategy": "UseIPv4"
}
}
},
@@ -192,7 +192,7 @@ lsmod | grep wireguard
```
::: tip
You can control the access method for corresponding users by modifying `"domainStrategy": "UseIPv6"`. Actual tests show priority is higher than the system's own `gai.config`.
You can control the access method for corresponding users by setting `sockopt.domainStrategy` to `UseIPv6`.
:::
## 5. System Settings Configuration
+4 -8
View File
@@ -52,12 +52,10 @@ sudo curl -oL /usr/local/share/xray/geosite.dat https://github.com/Loyalsoldier/
{
"tag": "direct",
"protocol": "freedom",
"settings": {
"domainStrategy": "UseIPv4"
},
"streamSettings": {
"sockopt": {
"mark": 2
"mark": 2,
"domainStrategy": "UseIPv4"
}
}
},
@@ -94,12 +92,10 @@ sudo curl -oL /usr/local/share/xray/geosite.dat https://github.com/Loyalsoldier/
"settings": {
"rewriteAddress": "8.8.8.8"
},
"proxySettings": {
"tag": "proxy"
},
"streamSettings": {
"sockopt": {
"mark": 2
"mark": 2,
"dialerProxy": "proxy"
}
}
}
@@ -93,12 +93,10 @@ If the Xray program is not installed on the side router, you can manually downlo
{
"tag": "direct",
"protocol": "freedom",
"settings": {
"domainStrategy": "UseIP"
},
"streamSettings": {
"sockopt": {
"mark": 255
"mark": 255,
"domainStrategy": "UseIP"
}
}
},
+16 -16
View File
@@ -4,23 +4,19 @@
Встроенный модуль DNS в Xray имеет три основных назначения:
- На этапе маршрутизации (Routing): резолвинг доменов в IP и сопоставление правил на основе полученных IP для разделения трафика. Будет ли выполняться резолвинг и разделение трафика, зависит от значения `domainStrategy` в конфигурации модуля маршрутизации. Встроенный DNS-сервер используется для запросов только при установке следующих двух значений:
- "IPIfNonMatch": при запросе домена сначала выполняется сопоставление по правилам `domain`. Если совпадений нет, выполняется запрос к встроенному DNS-серверу для получения IP, после чего снова выполняется сопоставление правил маршрутизации по IP.
- "IPOnDemand": при обнаружении любого правила, основанного на IP, домен немедленно резолвится в IP для сопоставления.
- На этапе маршрутизации: разрешение доменов в IP и сопоставление правил на основе полученных IP для разделения трафика.<br>
Разрешение домена для маршрутизации зависит от значения `routing.domainStrategy`. Встроенный DNS-сервер используется для запросов только при следующих значениях:
- `"IPIfNonMatch"`: если цель запроса задана доменным именем без сопутствующего IP, сначала выполняется проход сопоставления по остальным условиям. Если за этот проход не совпало ни одно правило маршрутизации, домен разрешается через встроенный DNS-сервер, после чего выполняется еще один проход сопоставления правил с использованием полученных IP-адресов.
- `"IPOnDemand"`: если цель запроса задана доменным именем без сопутствующего IP, при обнаружении правила, основанного на IP, домен сразу разрешается в IP для сопоставления.
- Резолвинг целевого адреса для подключения:
- Например, в `freedom` Outbound, если `domainStrategy` установлен в `UseIP`, запрос, исходящий из этого Outbound, сначала будет разрешен в IP через встроенный сервер, а затем произойдет подключение.
- Например, в `sockopt`, если `domainStrategy` установлен в `UseIP`, системное подключение, инициированное этим Outbound, сначала будет разрешено в IP встроенным сервером.
- На этапе исходящего подключения: разрешение целевых доменных имен для подключения или передачи удаленному прокси-серверу:
- Например, если в исходящем подключении VLESS задать `targetStrategy` равным `UseIP`, целевой домен проксируемого запроса сначала разрешается локальным встроенным модулем DNS, затем полученный IP передается удаленному прокси-серверу.
- Если в исходящем подключении VLESS задать `sockopt.domainStrategy` равным `UseIP`, домен сервера VLESS разрешается встроенным модулем DNS, затем устанавливается соединение с полученным IP.
- Если в исходящем подключении Freedom задать `sockopt.domainStrategy` равным `UseIP`, целевой домен запроса разрешается встроенным модулем DNS, затем устанавливается соединение с полученным IP.
- Протокол WireGuard не допускает передачу доменного имени в качестве цели, поэтому его исходящее подключение может использовать встроенный модуль DNS для разрешения доменов в IP.
- Перехват DNS-трафика в режиме TUN/Transparent Proxy через связку routing и DNS outbound, чтобы направлять DNS-трафик в этот модуль; либо работа в качестве рекурсивного DNS-сервера, открытого на порту 53.
::: tip TIP 1
DNS-сервер по умолчанию проходит сопоставление в системе маршрутизации, если только он не содержит `+local`. При использовании доменных имён внутри него обратите внимание на возможные петли (loop); может помочь `hosts`.
:::
::: tip TIP 2
Поддерживаются только базовые IP-запросы (записи A и AAAA). Записи CNAME будут запрашиваться повторно до тех пор, пока не будет возвращена запись A/AAAA. Другие типы запросов не попадают во встроенный DNS-сервер, а либо отбрасываются, либо передаются другим серверам в зависимости от вашей конфигурации Outbound.
:::
- Перехват DNS-трафика в режиме TUN/прозрачного прокси с помощью маршрутизации и исходящего подключения DNS для направления запросов в этот модуль; либо использование [Tunnel](./inbounds/tunnel.md) для открытия порта 53 и работы в качестве рекурсивного DNS-сервера.
- Поддерживаются только базовые IP-запросы (записи A и AAAA). Записи CNAME будут запрашиваться повторно до тех пор, пока не будет возвращена запись A/AAAA. Другие типы запросов не попадают во встроенный DNS-сервер, а либо отбрасываются, либо передаются другим серверам в зависимости от вашей конфигурации исходящего подключения.
## Процесс обработки DNS
@@ -136,6 +132,10 @@ DNS-клиенты, инициализированные различными п
(v1.4.0+) В [логах](./log.md) можно включить журналирование DNS-запросов.
:::
::: tip TIP 4
DNS-сервер по умолчанию проходит сопоставление в системе маршрутизации, если только он не содержит `+local`. При использовании доменных имён внутри него обратите внимание на возможные петли (loop); может помочь `hosts`.
:::
> `clientIp`: string
IP-адрес, используемый в расширении EDNS Client Subnet (ECS).
@@ -297,7 +297,7 @@ DNS-запросы, отправляемые модулем DNS, бывают д
Режим `local`: соединение устанавливается ядром напрямую во внешнюю сеть. Если адрес является доменом, он будет разрешен самой системой. Логика здесь проста.
Режим `non-local`: по умолчанию запрос рассматривается как входящий из Inbound с тегом `dns.tag` (не знаете где это? нажмите `ctrl+f` в браузере и найдите `inboundTag`). Он проходит через стандартный процесс обработки ядра и может быть направлен модулем маршрутизации в локальный `freedom` или другой удаленный Outbound. Там он будет разрешен согласно `domainStrategy` в `freedom` (осторожно, возможна петля) или передан в удаленный узел в виде домена для разрешения согласно методу сервера.
В режиме `non-local` DNS-запросы поступают в систему маршрутизации как внутренние запросы, а их `inboundTag` задается полем `tag` в конфигурации DNS. Если запрос направлен в локальное исходящее подключение Freedom, доменное имя самого DNS-сервера разрешается согласно `sockopt.domainStrategy` этого подключения (возможны петли). Если запрос направлен в исходящее подключение удаленного прокси, домен можно передать удаленной стороне для разрешения.
Поскольку обычным пользователям сложно разобраться в этой логике, рекомендуется (особенно в среде Transparent Proxy) напрямую указывать соответствующие IP для серверов с доменными именами в опции `hosts` модуля DNS, чтобы предотвратить возникновение петель (loop).
+4 -34
View File
@@ -20,10 +20,6 @@
"settings": {},
"tag": "тег",
"streamSettings": {},
"proxySettings": {
"tag": "another-outbound-tag",
"transportLayer": false
},
"mux": {},
"targetStrategy": "AsIs"
}
@@ -70,48 +66,22 @@ Xray будет использовать случайный IP-адрес из
Конфигурация транспорта для этого исходящего подключения.
> `proxySettings`: [ProxySettingsObject](#proxysettingsobject)
Конфигурация Outbound-прокси.
> `mux`: [MuxObject](#muxobject)
Настройки Mux. Mux позволяет мультиплексировать несколько TCP-соединений через одно TCP-соединение. У Mux есть дополнительная функция: передача UDP-соединений как XUDP.
> `targetStrategy`: "AsIs" | "UseIP" | "UseIPv6v4" | "UseIPv6" | "UseIPv4v6" | "UseIPv4" | "ForceIP" | "ForceIPv6v4" | "ForceIPv6" | "ForceIPv4v6" | "ForceIPv4"
Если при исходящем подключении отправляется запрос к доменному имени, эта опция управляет тем, будет ли оно разрешено (и каким образом) в IP-адрес для отправки.
Применяется к исходящим подключениям, кроме Freedom. Определяет, нужно ли локально разрешать целевое доменное имя проксируемого запроса в IP и какую стратегию разрешения использовать.
Значение по умолчанию — `AsIs`, то есть отправка на удаленный сервер «как есть». Значения всех параметров примерно соответствуют `domainStrategy` в [Sockopt](./transports/sockopt.md#sockoptobject).
Значение по умолчанию — `AsIs`: целевое доменное имя передается на удаленный сервер без изменений. Смысл стратегий в основном совпадает с `domainStrategy` в [Sockopt](./transports/sockopt.md#sockoptobject).
::: tip
Здесь контролируются **проксируемые запросы**. Если адресом исходящего прокси-сервера является доменное имя, и для этого домена необходимо выбрать стратегию разрешения, следует настроить `domainStrategy` в [Sockopt](./transports/sockopt.md#sockoptobject).
Стратегию разрешения доменных имен для Freedom также следует задавать через `sockopt.domainStrategy`.
:::
### ProxySettingsObject
```json
{
"tag": "another-outbound-tag",
"transportLayer": false
}
```
> `tag`: string
Если указан тег другого Outbound, данные, исходящие из этого Outbound, будут перенаправлены через указанный Outbound.
::: danger
Эта опция конфликтует с [Sockopt.dialerProxy](./transports/sockopt.md#sockoptobject), используйте только один из этих вариантов по необходимости.
По умолчанию этот способ пересылки **игнорирует** собственную конфигурацию транспорта этого outbound (например XHTTP, REALITY или Sockopt), поэтому `streamSettings` у данного outbound не будут работать.<br>
Если вам нужна пересылка с поддержкой `streamSettings`, используйте `Sockopt.dialerProxy` или установите здесь `transportLayer` в `true`.
:::
> `transportLayer`: true | false
`true` преобразует эту настройку в `Sockopt.dialerProxy`, чтобы пересылка использовала `streamSettings` этого outbound. По умолчанию `false`.
### MuxObject
Функция Mux позволяет мультиплексировать несколько TCP-соединений по одному TCP-соединению.
+74 -44
View File
@@ -1,6 +1,6 @@
# Freedom (fragment, noises)
Freedom — это исходящий протокол, который можно использовать для отправки (обычных) данных TCP или UDP в любую сеть.
Freedom — это протокол прямого исходящего подключения, обычно являющийся конечной точкой обработки трафика: он принимает поступающий трафик TCP или UDP, напрямую устанавливает соединение с конечным адресом назначения и передает и принимает данные.
::: warning
Для этого outbound на стороне сервера и обратного прокси действует политика безопасности по умолчанию, которая может блокировать некоторые цели; способ разрешения см. ниже в `finalRules`.
@@ -16,9 +16,8 @@ Freedom — это исходящий протокол, который можн
{
// ...
"protocol": "freedom",
// [!code focus:29]
// [!code focus:28]
"settings": {
"domainStrategy": "AsIs",
"redirect": "127.0.0.1:3366",
"userLevel": 0,
"fragment": {
@@ -51,26 +50,18 @@ Freedom — это исходящий протокол, который можн
}
```
> `domainStrategy`: "AsIs"
> "UseIP" | "UseIPv6v4" | "UseIPv6" | "UseIPv4v6" | "UseIPv4"
> "ForceIP" | "ForceIPv6v4" | "ForceIPv6" | "ForceIPv4v6" | "ForceIPv4"
Значение по умолчанию — `"AsIs"`.
Все параметры по смыслу аналогичны `domainStrategy` в [Sockopt](../transports/sockopt.md#sockoptobject).
Только использование `AsIs` в этом разделе позволяет передать доменное имя в последующий модуль `sockopt`. Если установить значение, отличное от `AsIs`, домен будет разрешен в конкретный IP, что сделает последующие настройки `sockopt.domainStrategy` и связанный с ними механизм `happyEyeballs` недействительными. (Если вы не изменяли эти настройки, негативного влияния не будет).
По определенным причинам при отправке UDP протокол Freedom игнорирует `domainStrategy` в `sockopt` и по умолчанию принудительно отдает предпочтение IPv4.
::: tip
Стратегия разрешения целевого доменного имени в Freedom задается параметром [sockopt.domainStrategy](../transports/sockopt.md#sockoptobject).
:::
> `redirect`: address_port
Freedom будет принудительно отправлять все данные на указанный адрес (а не на адрес, указанный во входящем соединении).
Freedom заменяет текущие адрес и порт назначения соединения на адрес и порт, указанные в `redirect`.
Значение — строка, например: `"127.0.0.1:80"`, `":1234"`.
Если адрес не указан, например `":443"`, Freedom не будет изменять исходный целевой адрес.
Если порт равен `0`, например `"xray.com: 0"`, Freedom не будет изменять исходный порт.
Если порт равен `0`, например `"xray.com:0"`, Freedom не будет изменять исходный порт.
> `userLevel`: number
@@ -78,35 +69,15 @@ Freedom будет принудительно отправлять все дан
Значение `userLevel` соответствует значению `level` в [policy](../policy.md#policyobject). Если не указано, по умолчанию используется значение `0`.
> `fragment`: map
> `fragment`: [FragmentObject](#fragmentobject)
Несколько пар «ключ-значение», используемых для управления исходящей фрагментацией TCP. В некоторых случаях это может обмануть системы цензуры, например, обойти черные списки SNI.
`"length"` и `"interval"` относятся к типу [Int32Range](../../development/intro/guide.md#int32range)
`"packets"`: поддерживаются два режима фрагментации: "1-3" — фрагментация потока TCP, применяется к первым трем операциям записи данных на стороне клиента; "tlshello" — фрагментация пакета TLS-рукопожатия.
`"length"`: длина фрагмента (в байтах).
`"interval"`: интервал между фрагментами (в мс).
Если значение равно `0` и установлено `"packets": "tlshello"`, фрагментированный пакет Client Hello будет отправлен в одном TCP-пакете (если его исходный размер не превышает MSS или MTU, что приводит к автоматической фрагментации системой).
> `noises`: array
> `noises`: \[ [NoiseObject](#noiseobject) \]
UDP-шум, используемый для отправки случайных данных в качестве "шума" перед установлением UDP-соединения. Наличие этой структуры считается включением. Это может обмануть снифферы, но также может нарушить нормальное соединение. Используйте на свой страх и риск. По этой причине он обходит порт 53, так как это нарушает работу DNS.
Массив, в котором можно определить несколько пакетов шума для отправки. Отдельный элемент массива определяется следующим образом:
`"type"`: тип пакета шума. В настоящее время поддерживаются `"rand"` (случайные данные), `"str"` (пользовательская строка) и `"base64"` (пользовательские двоичные данные, закодированные в Base64).
`"packet"`: содержимое пакета данных, основанное на предыдущем значении `type`.
- Если `type` равен `rand`, здесь указывается длина случайных данных. Это может быть фиксированное значение, например `"100"`, или диапазон значений, например `"50-150"`.
- Если `type` равен `str`, здесь указывается строка для отправки.
- Если `type` имеет значение `hex`, здесь указываются двоичные данные в шестнадцатеричном представлении.
- Если `type` равен `base64`, здесь указываются двоичные данные, закодированные в Base64.
`"delay"`: **задержка**, в миллисекундах. После отправки этого пакета шума ядро будет ждать указанное время, прежде чем отправить следующий пакет шума или реальные данные. По умолчанию ожидание отсутствует. Тип: [Int32Range](../../development/intro/guide.md#int32range)
Массив, в котором можно определить несколько пакетов шума для отправки. Каждый элемент — это [NoiseObject](#noiseobject).
> `proxyProtocol`: number
@@ -114,13 +85,23 @@ UDP-шум, используемый для отправки случайных
`proxyProtocol` принимает значение номера версии протокола PROXY — `1` или `2`. Если не указано, по умолчанию используется значение `0` (протокол не используется).
> `finalRules`: \[[FinalRuleObject](#finalruleobject)\]
> `finalRules`: \[ [FinalRuleObject](#finalruleobject) \]
Последовательно сопоставляет финальные правила Freedom и разрешает или блокирует целевые соединения.
По сравнению с блокировкой в `routing`, `finalRules` применяется на финальном этапе исходящего соединения Freedom: сопоставление выполняется после разрешения конечного IP и до дозвона; кроме того, для UDP сопоставление также выполняется для каждого пакета при отправке и приеме, поэтому работает строже и надежнее. Сопоставление каждого правила занимает около 50-150 нс.
По сравнению с блокировкой в `routing`, `finalRules` применяется на финальном этапе исходящего соединения Freedom, до и после установления соединения. Кроме того, для UDP проверяется каждый пакет при отправке и приеме, что делает проверку более строгой и полной. Сопоставление с каждым правилом занимает около 50-150 нс, поэтому беспокоиться о производительности не стоит.
Обратите внимание: всякий раз, когда Freedom должен применять `finalRules`, если `domainStrategy` имеет значение `AsIs`, а целью является домен, Freedom все равно сначала разрешает цель в IP через системный DNS, а затем выполняет сопоставление правил. После этого цель уже не является доменом, поэтому последующий `sockopt.domainStrategy` и связанный с ним `happyEyeballs` больше не применяются.
::: details Если цель — доменное имя
Если цель задана доменным именем и требуется применить правила, Freedom перед установлением соединения разрешает домен согласно `sockopt.domainStrategy`, затем проверяет каждый полученный IP по правилам в указанном порядке. Если заблокирован хотя бы один IP, блокируется весь запрос.
После успешного установления соединения Freedom повторно проверяет по правилам фактический IP удаленной стороны. Поэтому, если предварительное разрешение не удалось или результаты двух разрешений различаются, пакеты TCP-рукопожатия все же могут быть отправлены до перехода соединения в состояние черной дыры.
При отправке каждого UDP-пакета, адресованного доменному имени, домен также разрешается. Однако проверка отдельного пакета сопоставляет с правилами по порядку только выбранный для этого пакета IP назначения и решает, нужно ли его блокировать; все полученные при разрешении IP при этом не проверяются.
:::
::: tip
Если для этого исходящего подключения настроен `sockopt.dialerProxy`, Freedom больше не является конечным исходящим подключением, поэтому `finalRules` и описанная ниже политика безопасности по умолчанию не применяются.
:::
::: warning
На стороне сервера и обратного прокси действует резервная политика безопасности по умолчанию:
@@ -128,10 +109,59 @@ UDP-шум, используемый для отправки случайных
Если ни одно явное правило не совпало, используется встроенное резервное правило: трафик от обратного прокси VLESS по умолчанию блокирует все цели; трафик от входящих `VLESS`, `VMess`, `Trojan`, `Shadowsocks`, `Hysteria` или `WireGuard` по умолчанию блокирует частные и зарезервированные диапазоны IP; прочий трафик по умолчанию полностью разрешается.
Если серверу нужно разрешить клиентам доступ к некоторым внутренним сервисам, явно настройте правила `allow` и по возможности разрешайте только необходимые `network`, `ip` и `port`.
Если серверу также нужны возможности, которые зависят от передачи доменного имени в `sockopt` (например, `sockopt.domainStrategy` или `happyEyeballs`), то использовать эту политику безопасности по умолчанию дальше нельзя. Можно задать первым правило `allow` без каких-либо условий сопоставления, чтобы восстановить прежнее поведение; это также эквивалентно отключению этой политики безопасности по умолчанию, поэтому оцените последствия для безопасности самостоятельно.
:::
### FragmentObject
```json
{
"packets": "tlshello",
"length": "100-200",
"interval": "10-20"
}
```
> `packets`: string
Поддерживаются два режима фрагментации: `"1-3"` — фрагментация потока TCP, применяется к первым трем операциям записи данных на стороне клиента; `"tlshello"` — фрагментация пакета TLS-рукопожатия.
> `length`: [Int32Range](../../development/intro/guide.md#int32range)
Длина фрагмента (в байтах).
> `interval`: [Int32Range](../../development/intro/guide.md#int32range)
Интервал между фрагментами (в мс).
Если значение равно `0` и установлено `"packets": "tlshello"`, фрагментированный пакет Client Hello будет отправлен в одном TCP-пакете (если его исходный размер не превышает MSS или MTU, что приводит к автоматической фрагментации системой).
### NoiseObject
```json
{
"type": "base64",
"packet": "7nQBAAABAAAAAAAABnQtcmluZwZtc2VkZ2UDbmV0AAABAAE=",
"delay": "10-16"
}
```
> `type`: string
Тип пакета шума. В настоящее время поддерживаются `"rand"` (случайные данные), `"str"` (пользовательская строка) и `"base64"` (пользовательские двоичные данные, закодированные в Base64).
> `packet`: string
Содержимое пакета данных, основанное на предыдущем значении `type`.
- Если `type` равен `rand`, здесь указывается длина случайных данных. Это может быть фиксированное значение, например `"100"`, или диапазон значений, например `"50-150"`.
- Если `type` равен `str`, здесь указывается строка для отправки.
- Если `type` имеет значение `hex`, здесь указываются двоичные данные в шестнадцатеричном представлении.
- Если `type` равен `base64`, здесь указываются двоичные данные, закодированные в Base64.
> `delay`: [Int32Range](../../development/intro/guide.md#int32range)
Задержка в миллисекундах. После отправки этого пакета шума ядро ждет указанное время, прежде чем отправить следующий пакет шума или реальные данные. По умолчанию ожидание отсутствует.
### FinalRuleObject
```json
+1 -1
View File
@@ -5,7 +5,7 @@ Loopback — это outbound с возвратом трафика, которы
::: tip Применение
- В местах, где можно указать только outbound и нельзя напрямую задать `balancerTag`, Loopback позволяет косвенно использовать балансировщик.<br>
Например, `proxySettings` и `dialerProxy` в цепочках прокси, а также `fallbackTag` при балансировке нагрузки.
Например, `dialerProxy` в цепочках прокси, а также `fallbackTag` при балансировке нагрузки.
- После того как трафик уже был разделен один раз, его можно дополнительно детализировать по другим условиям.<br>
Например, TCP- и UDP-трафик, разделенные одной и той же группой правил routing, можно направить в разные outbound.
+2 -2
View File
@@ -98,9 +98,9 @@ MTU нижнего уровня tun в Wireguard.
Управляет стратегией разрешения доменных имен, когда адрес сервера Wireguard является доменным именем или целевой адрес проксируемого трафика является доменным именем.
В отличие от большинства прокси-протоколов, Wireguard не позволяет передавать доменные имена в качестве целей. Если в качестве цели передается доменное имя, оно разрешается в IP-адрес через встроенный DNS Xray. Подробнее см. поле `domainStrategy` для outbound `Freedom`. По умолчанию используется `ForceIP`.
В отличие от большинства прокси-протоколов, Wireguard не позволяет передавать доменные имена в качестве целей. Если цель задана доменным именем, перед передачей его необходимо разрешить в IP. Значения этого поля соответствуют стратегиям `Force` в [sockopt.domainStrategy](../transports/sockopt.md#sockoptobject). По умолчанию используется `ForceIP`.
В настройках `domainStrategy` outbound `Freedom` доступны опции, такие как `UseIP`, которые здесь отсутствуют, так как Wireguard должен получить действительный IP-адрес и не может выполнять откат к доменному имени после неудачного разрешения `UseIP`.<br>
В `sockopt.domainStrategy` доступны опции, такие как `UseIP`, которые здесь отсутствуют, так как Wireguard должен получить действительный IP-адрес и не может выполнять откат к доменному имени после неудачного разрешения `UseIP`.<br>
Примечание: при применении к проксируемому трафику эта опция также ограничивается опцией `address`. Например, если вы установили `ForceIPv6v4`, но в `address` не задан IPv6-адрес, то даже при наличии у целевого домена AAAA-записей они не будут разрешены.
### Peers
+28 -28
View File
@@ -93,27 +93,36 @@ Sockopt используется для настройки низкоуровн
Значение по умолчанию — `"AsIs"`.
Когда целевой адрес является доменным именем, это поле управляет тем, как outbound будет его разрешать и использовать:
Если адрес, к которому должно подключиться исходящее соединение, является доменным именем, эта настройка управляет способом его разрешения:
- При `"AsIs"` Xray никак специально не обрабатывает доменное имя и в конце использует обычный dialer Go. Приоритет фиксирован правилами RFC 6724 и обычно приводит к предпочтению IPv6.
- При любом другом значении Xray использует [встроенный DNS](../dns.md). Если `DNSObject` отсутствует, используется системный DNS. Если есть несколько подходящих IP-адресов, ядро случайным образом выбирает один.
- При `"AsIs"` Xray передает домен Go, который разрешает его с использованием DNS-настроек операционной системы и устанавливает соединение. Для TCP обычно сначала пробуется IPv6, а при затруднениях с подключением — IPv4; для UDP предпочтителен IPv4.
::: details Выбор адреса и переход между семействами при AsIs
TCP использует встроенный в Go механизм Happy Eyeballs. Предпочтительным считается семейство первого адреса в результатах разрешения. Если за 300 мс соединение не установлено, начинаются попытки с другим семейством адресов. Если все попытки с предпочтительным семейством завершились ошибкой раньше, другое семейство пробуется немедленно. Настройка Xray `sockopt.happyEyeballs` на это не влияет. См. [реализацию подключения в Go](https://go.dev/src/net/dial.go).
В сборках Xray на чистом Go адреса сортируются по упрощенным правилам RFC 6724: при прочих равных обычно предпочтителен IPv6, а `/etc/gai.conf` не читается. Большинство официальных релизных сборок Xray используют этот подход; в некоторых операционных системах или сторонних сборках поведение может немного отличаться. См. [реализацию сортировки адресов в Go](https://go.dev/src/net/addrselect.go).
UDP предпочитает IPv4 из результатов разрешения и выбирает IPv6 только при отсутствии IPv4. Ошибка отправки не вызывает автоматического перехода на другое семейство адресов. Это поведение действует и при откате стратегии `Use` к `AsIs`. См. [реализацию выбора UDP-адреса в Go](https://go.dev/src/net/ipsock.go).
:::
- При любом другом значении используется [встроенный модуль DNS](../dns.md) Xray. Если `DNSObject` не настроен, используется системный DNS. Если подходят несколько IP-адресов, по умолчанию один выбирается случайно; при включенном `sockopt.happyEyeballs` для TCP выбор выполняется с помощью гонки подключений.
- `"IPv4"` означает разрешение только IPv4. `"IPv4v6"` означает, что сначала разрешается IPv4, а IPv6 разрешается только в том случае, если разрешение IPv4 завершилось ошибкой или не вернуло ни одного IP-адреса. Если IPv4-адреса уже получены, последующая ошибка подключения не приводит к переходу на IPv6. Для `"IPv6"` и `"IPv6v4"` действует та же логика, но порядок семейств адресов обратный.
- Если во встроенном DNS также задан `"queryStrategy"`, фактическое поведение определяется пересечением двух настроек. Например, `"queryStrategy": "UseIPv4"` вместе с `"domainStrategy": "UseIP"` фактически эквивалентно `"domainStrategy": "UseIPv4"`.
- Варианты `"Use*"` делают fallback к `"AsIs"`, если результат разрешения не соответствует нужному семейству адресов.
- Варианты `"Force*"` завершают соединение ошибкой, если получить нужный тип адреса не удалось.
- Если во встроенном модуле DNS задан `"queryStrategy"`, типы разрешаемых IP определяются пересечением двух настроек: разрешаются только типы, допускаемые обеими. Например, `"queryStrategy": "UseIPv4"` вместе с `"domainStrategy": "UseIP"` фактически эквивалентно `"domainStrategy": "UseIPv4"`.
- Варианты с префиксом `"Use"` возвращаются к `AsIs`, если разрешение завершилось ошибкой или результаты не соответствуют требованиям, например если домен разрешается только в IPv4, а выбрано `UseIPv6`.
- При вариантах с префиксом `"Force"` соединение не устанавливается, если разрешение завершилось ошибкой или результаты не соответствуют требованиям.
::: tip TIP
::: tip
Если используется `"UseIP"` или `"ForceIP"` и в [OutboundObject](../outbound.md#outboundobject) задан `sendThrough`, ядро автоматически определяет нужное семейство адресов по локальному адресу. Если вручную зафиксировать, например, `UseIPv4`, а `sendThrough` указывает на IPv6-адрес, соединение завершится ошибкой.
:::
::: danger
Неправильная настройка этой функции может привести к бесконечному циклу.
:::: danger Неправильная настройка этой функции может привести к бесконечному циклу!
Чтобы подключиться к серверу, нужно дождаться результата DNS-запроса, а чтобы завершить DNS-запрос, нужно подключиться к серверу.
Коротко: чтобы подключиться к серверу, нужно дождаться DNS-результата, а чтобы завершить DNS-запрос, нужно подключиться к серверу.
Неопытным пользователям **не рекомендуется** использовать эту функцию без понимания маршрутизации.
Подробно:
::: details Подробное объяснение
1. Есть прокси-сервер `proxy.com` и встроенный DNS в не-Local режиме.
1. Адрес прокси-сервера — доменное имя (`proxy.com`), а встроенный DNS-сервер работает в режиме, отличном от Local.
2. Перед подключением к `proxy.com` Xray сначала пытается разрешить `proxy.com` через встроенный DNS.
3. Встроенный DNS устанавливает соединение с `dns.com`, чтобы узнать IP-адрес `proxy.com`.
4. Неудачные правила маршрутизации отправляют запрос из шага 3 через `proxy.com`.
@@ -129,16 +138,12 @@ Sockopt используется для настройки низкоуровн
- Использовать hosts.
- ~~Если вы до сих пор не понимаете решение, не включайте эту функцию.~~
Поэтому неопытным пользователям использовать эту возможность без понимания маршрутизации не рекомендуется.
:::
::::
> `dialerProxy`: ""
Идентификатор outbound. Если поле не пустое, для установления соединения используется указанный outbound. Это позволяет делать цепочку с учетом транспортных настроек.
::: danger
Эта настройка несовместима с `ProxySettingsObject.Tag`.
:::
Идентификатор исходящего подключения. Если поле не пустое, для установления соединения используется указанное исходящее подключение. Обычно применяется для настройки цепочек прокси.
> `acceptProxyProtocol`: true | false
@@ -205,10 +210,6 @@ Xray проверяет, присутствуют ли в запросе заг
Значение по умолчанию — `false`. Если установить `true`, включается [Multipath TCP](https://en.wikipedia.org/wiki/Multipath_TCP). Параметр относится только к клиентской стороне, поскольку начиная с Go 1.24 прослушивание уже включает MPTCP по умолчанию. Требуется Linux kernel 5.6 или новее.
> `tcpNoDelay`: true | false
Этот параметр удален, потому что Go и так включает TCP no delay по умолчанию. Если вам нужно отключить его, используйте `customSockopt`.
> `addressPortStrategy`: "none" | "SrvPortOnly" | "SrvAddressOnly" | "SrvPortAndAddress" | "TxtPortOnly" | "TxtAddressOnly" | "TxtPortAndAddress"
Позволяет использовать SRV- или TXT-записи для задания адреса и или порта цели для outbound. По умолчанию используется `none`, то есть функция выключена.
@@ -219,9 +220,9 @@ Xray проверяет, присутствуют ли в запросе заг
`PortOnly` заменяет только порт. `AddressOnly` — только адрес. `PortAndAddress` — и адрес, и порт.
Эта настройка применяется раньше `domainStrategy` внутри `sockopt`. После подмены адрес по-прежнему проходит через `domainStrategy`, если он задан. Но применяется она уже после `Freedom.domainStrategy`, поэтому если `Freedom` заранее разрешил домен в IP, этот механизм уже не сработает.
Эта настройка применяется до разрешения адреса через `sockopt.domainStrategy`. После замены адрес по-прежнему разрешается согласно `domainStrategy`.
На практике это означает, что если обычный доменный трафик попадает в `Freedom` с `AsIs`, после включения этого параметра ядро начнет пытаться переписать адрес и порт, например через SRV-запись `google.com`.
Исходящие подключения Freedom не поддерживают эту настройку.
> `customSockopt`: []
@@ -272,13 +273,12 @@ Xray проверяет, присутствуют ли в запросе заг
> `happyEyeballs`: [HappyEyeballsObject](#happyeyeballsobject)
Реализация Happy Eyeballs по RFC 8305, только для TCP. Когда целью является доменное имя, Xray запускает гонку между разрешенными адресами и выбирает первый успешный. Работает только если `Sockopt.domainStrategy` не равен `AsIs`.
Реализация Happy Eyeballs по RFC 8305, только для TCP. Когда целью является доменное имя, Xray запускает гонку между разрешенными адресами и выбирает первый успешный. Работает только если `sockopt.domainStrategy` не равен `AsIs`.
Значения `UseIPv4v6` и `ForceIPv4v6` фактически сокращают список доступных IP-адресов до IPv4 и переходят к разрешению IPv6 только в том случае, если разрешение IPv4 завершилось ошибкой или не вернуло ни одного IP-адреса. Ошибка подключения по IPv4 не запускает этот переход. Такое использование не рекомендуется. Лучше использовать `UseIP` или `ForceIP` вместе с `HappyEyeballs.interleave`.
Значения `UseIPv4v6` и `ForceIPv4v6` фактически сокращают список доступных IP-адресов до IPv4 и переходят к разрешению IPv6 только в том случае, если разрешение IPv4 завершилось ошибкой или не вернуло ни одного IP-адреса. Ошибка подключения по IPv4 не запускает этот переход. Такое использование не рекомендуется. Лучше использовать `UseIP` или `ForceIP` вместе с `happyEyeballs.interleave`.
::: warning
Не используйте эту функцию вместе с `targetStrategy` этого outbound, потому что тогда `Sockopt` увидит только конечный IP после подмены.<br>
Также ее нельзя использовать вместе с `dialerProxy`, иначе `happyEyeballs` не сработает.
Нельзя использовать эту функцию вместе с `dialerProxy`, иначе `happyEyeballs` не сработает.
:::
### HappyEyeballsObject
+4 -4
View File
@@ -34,16 +34,16 @@
Рационально используя мощные возможности встроенного DNS в Xray (Fallback, ECS, фильтрация по IP, тегирование), и тщательно настраивая порядок серверов, вы получите IP-адрес как условие маршрутизации, который будет гораздо точнее и актуальнее, чем `geosite cn/!cn`. Это связано с тем, что принадлежность IP к региону (GeoIP), особенно к Китаю, меняется довольно редко.
Прежде чем продолжить чтение, вам необходимо внимательно изучить и понять: "Основы: Краткий анализ функции маршрутизации (routing) — [Часть 1](./routing-lv1-part1.md), [Часть 2](./routing-lv1-part2.md)".
Предполагается, что вы уже досконально изучили официальное руководство по конфигурации и полностью понимаете работу `domainStrategy` в Routing и Outbound, назначение опций `sniffing` в Inbound, а также поведение системы при различных комбинациях этих параметров.
Предполагается, что вы уже досконально изучили официальное руководство по конфигурации и полностью понимаете работу `domainStrategy` в Routing и `sockopt`, назначение `targetStrategy` в Outbound, назначение опций `sniffing` в Inbound, а также поведение системы при различных комбинациях этих параметров.
Всё готово? Попробуйте осмыслить следующий абзац:
При входящих соединениях `socks` или `http` запрашивается домен. Когда запрос попадает в Routing, стратегия `domainStrategy` (если она отлична от `AsIs`) может использовать встроенный DNS для резолвинга IP, который временно используется для сопоставления правил маршрутизации. При отправке в локальный `direct` Outbound, если его `domainStrategy` не `AsIs`, встроенный DNS снова резолвит IP для исходящего соединения. Запрос, отправляемый на удаленный сервер Xray, содержит только домен; какой именно IP будет использован для доступа, зависит от `direct` Outbound на сервере.
При входящих соединениях `socks` или `http` исходный запрос адресован домену. Когда запрос попадает в модуль маршрутизации, `domainStrategy`, отличный от `AsIs`, может использовать встроенный DNS для разрешения IP, временно используемых при сопоставлении правил. Если трафик направлен в локальный `direct` Outbound, `domainStrategy` в `sockopt`, отличный от `AsIs`, может снова использовать встроенный DNS для разрешения IP исходящего соединения. Если трафик направлен на удаленный сервер Xray и `targetStrategy` локального Outbound равен `AsIs`, цель запроса по-прежнему передается в виде домена; какой именно IP будет использован, зависит от `direct` Outbound на сервере.
В режиме прозрачного прокси (Transparent Proxy) ситуация сложнее. Если включен `sniffing` на Inbound и `destOverride` содержит `[http, tls]`:
- Если `routeOnly = false`, запрошенный IP будет стерт, и дальнейший процесс аналогичен `socks` Inbound.
- Если `routeOnly = true`, то доступны и домен, и IP. В Routing можно напрямую сопоставлять правила по домену и IP, а локальный `direct` Outbound также будет использовать этот IP. Запрос к серверу Xray содержит только IP. Как сервер его обработает? Повторит описанный выше процесс.
- Если `routeOnly = true`, то доступны и домен, и IP. В модуле маршрутизации можно напрямую сопоставлять правила по домену и IP, а локальный `direct` Outbound также будет использовать этот IP. Запрос к серверу Xray содержит только IP. Как сервер его обработает? Повторит описанный выше процесс.
Возникли трудности? Вам нужно вернуться к официальному руководству и попытаться вникнуть. В противном случае вам будет сложно использовать результаты резолвинга DNS-модуля из примеров ниже для правильной маршрутизации.
@@ -266,7 +266,7 @@ graph TD
В этом сценарии, поскольку все запросы к серверу Xray передаются в виде доменов, нет необходимости использовать DNS для многократного поиска оптимального результата. Достаточно быстро определить, не "загрязнен" ли домен, и по возможности получить китайский IP, дружественный к CDN.
В этом примере китайский IP, полученный DNS-модулем, уже на 99% оптимизирован для CDN в Китае. Поэтому вы можете установить `domainStrategy` в `direct` Outbound в значение **не** `AsIs`, чтобы использовать кэш, если это необходимо.<br>
В этом примере китайский IP, полученный DNS-модулем, уже на 99% оптимизирован для CDN в Китае. Поэтому вы можете установить `sockopt.domainStrategy` в `direct` Outbound в значение **не** `AsIs`, чтобы использовать кэш, если это необходимо.<br>
Если вы стремитесь к 100% оптимизации для китайских CDN, можно установить `AsIs`, чтобы использовать системный DNS для повторного резолвинга (дополнительные затраты времени от 1 до сотен мс). Рекомендуется включить "оптимистичное кэширование" (optimistic caching) для дальнейшего снижения задержки.
## Послесловие
+13 -14
View File
@@ -113,8 +113,10 @@ lsmod | grep wireguard
"outbounds": [
{
"protocol": "freedom",
"settings": {
"domainStrategy": "UseIPv4"
"streamSettings": {
"sockopt": {
"domainStrategy": "UseIPv4"
}
}
// Измените на UseIPv4 или UseIPv6 по вашему выбору
},
@@ -124,11 +126,9 @@ lsmod | grep wireguard
"tag": "wg0",
"streamSettings": {
"sockopt": {
"mark": 255 // <mark>
"mark": 255, // <mark>
"domainStrategy": "UseIPv6"
}
},
"settings": {
"domainStrategy": "UseIPv6"
}
}, // Трафик с меткой fwmark, равной <mark>, будет направлен через UseIPv6/UseIPv4.
// <--Выберите один из вариантов--> Вариант 2: sendThrough
@@ -137,8 +137,10 @@ lsmod | grep wireguard
"protocol": "freedom",
"sendThrough": "your wg0 v4 address",
// Измените на UseIPv4 или UseIPv6 по вашему выбору
"settings": {
"domainStrategy": "UseIPv4"
"streamSettings": {
"sockopt": {
"domainStrategy": "UseIPv4"
}
}
// Измените на UseIPv4 или UseIPv6 по вашему выбору
},
@@ -146,12 +148,10 @@ lsmod | grep wireguard
{
"tag": "wg0",
"protocol": "freedom",
"settings": {
"domainStrategy": "UseIPv4"
},
"streamSettings": {
"sockopt": {
"interface": "wg0"
"interface": "wg0",
"domainStrategy": "UseIPv4"
}
}
},
@@ -193,8 +193,7 @@ lsmod | grep wireguard
```
::: tip
Вы можете изменить "domainStrategy": "UseIPv6", чтобы управлять способом доступа для определенных пользователей.
По моим тестам, этот параметр имеет более высокий приоритет, чем gai.config в системе.
Вы можете управлять способом доступа для соответствующих пользователей, задав `sockopt.domainStrategy` равным `UseIPv6`.
:::
## 5. Настройка системы
+4 -8
View File
@@ -53,12 +53,10 @@ sudo curl -oL /usr/local/share/xray/geosite.dat https://github.com/Loyalsoldier/
{
"tag": "direct",
"protocol": "freedom",
"settings": {
"domainStrategy": "UseIPv4"
},
"streamSettings": {
"sockopt": {
"mark": 2
"mark": 2,
"domainStrategy": "UseIPv4"
}
}
},
@@ -95,12 +93,10 @@ sudo curl -oL /usr/local/share/xray/geosite.dat https://github.com/Loyalsoldier/
"settings": {
"rewriteAddress": "8.8.8.8"
},
"proxySettings": {
"tag": "proxy"
},
"streamSettings": {
"sockopt": {
"mark": 2
"mark": 2,
"dialerProxy": "proxy"
}
}
}
@@ -94,12 +94,10 @@
{
"tag": "direct",
"protocol": "freedom",
"settings": {
"domainStrategy": "UseIP"
},
"streamSettings": {
"sockopt": {
"mark": 255
"mark": 255,
"domainStrategy": "UseIP"
}
}
},