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 @@
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"
}
}
},