From e35d91d8f0d3038aecdc0daa75e85d9377e69f24 Mon Sep 17 00:00:00 2001 From: patterniha <71074308+patterniha@users.noreply.github.com> Date: Thu, 26 Jun 2025 13:14:40 +0330 Subject: [PATCH 1/7] English only: add happyEyeballs --- docs/en/config/transport.md | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/docs/en/config/transport.md b/docs/en/config/transport.md index 42d78c85cd..707e8d9dc8 100644 --- a/docs/en/config/transport.md +++ b/docs/en/config/transport.md @@ -26,6 +26,7 @@ Transports specify how to achieve stable data transmission. Both ends of a conne "tcpFastOpen": false, "tproxy": "off", "domainStrategy": "AsIs", + "happyEyeballs": {"tryDelayMs": 250}, "dialerProxy": "", "acceptProxyProtocol": false, "tcpKeepAliveInterval": 0, @@ -461,6 +462,7 @@ A string array representing the key content, in the format shown in the example. "tcpFastOpen": false, "tproxy": "off", "domainStrategy": "AsIs", + "happyEyeballs": {"tryDelayMs": 250}, "dialerProxy": "", "acceptProxyProtocol": false, "tcpKeepAliveInterval": 0, @@ -643,3 +645,47 @@ The option name of the operation, using decimal (the example here is that the va The option value to be set, the example here is set to bbr. Decimal numbers are required when type is specified as int. + + +> `happyEyeballs`: {} + +only TCP, this is RFC-8305 implementation of happyEyeballs, only apply when built-in-dns is used(domainStrategy is `UseIP`/`ForceIP`). +When we have multiple IPs, this algorithm tries to connect to each IP, the first-stablished-connection is winner connection and selected for sending/receiving data. + +::: warning + +in `freedom` settings when you set `domainStrategy` to `UseIP`/`ForceIP` just a random IP will replace the domain and `happyEyeballs` does not apply, so for using `happyEyeballs` you should set `sockopt domainStrategy` to `UseIP/ForceIP` not `freedom domainStrategy`. + +::: + +::: tip + +in `AsIs` domainStrategy, built-in golang happyEyeballs is applied(currently it is RFC-6555) + +::: + +```json +"happyEyeballs": { + "tryDelayMs": 250, + "prioritizeIPv6": false, + "maxConcurrentTry": 4, + "interleave": 1 +} +``` + +> `tryDelayMs`: number + +delay time between each attempt in millisecond, RFC-8305 recommend `250`, default is `0`. +(if it is `0`, happy-eyeballs is disabled) + +> `interleave`: number + + indicate "First Address Family count" in RFC-8305, default is 1. + +> `prioritizeIPv6`: bool + + indicate "First Address Family" in RFC-8305, default is false(= prioritizeIPv4) + +> `maxConcurrentTry`: number + +maximum concurrent attempt (this is only maximum and in most cases our concurrent attempts is less, unless all connection fail to connect) also we can always have a maximum of concurrent-attempt as many IPs as we have, and this option is useful when the number of IPs is too high, and we want to control the number of concurrent-attempts, default is 4. if it is 0, happy-eyeballs is disabled. From b7651cc5365c1fb717ff9a67f015d611b7f56761 Mon Sep 17 00:00:00 2001 From: patterniha <71074308+patterniha@users.noreply.github.com> Date: Thu, 26 Jun 2025 13:22:03 +0330 Subject: [PATCH 2/7] add dialerProxy-tip --- docs/en/config/transport.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/en/config/transport.md b/docs/en/config/transport.md index 707e8d9dc8..b560f270c2 100644 --- a/docs/en/config/transport.md +++ b/docs/en/config/transport.md @@ -664,6 +664,12 @@ in `AsIs` domainStrategy, built-in golang happyEyeballs is applied(currently it ::: +::: tip + +when `dialerProxy` is set `happyEyeballs` is not applied, and only a random IP will replace the domain. + +::: + ```json "happyEyeballs": { "tryDelayMs": 250, From fd673c0d53248946befd1c5d3854d5bc8bfb8cc2 Mon Sep 17 00:00:00 2001 From: patterniha <71074308+patterniha@users.noreply.github.com> Date: Thu, 26 Jun 2025 13:35:47 +0330 Subject: [PATCH 3/7] Update transport.md --- docs/en/config/transport.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/docs/en/config/transport.md b/docs/en/config/transport.md index b560f270c2..c6331af576 100644 --- a/docs/en/config/transport.md +++ b/docs/en/config/transport.md @@ -673,9 +673,9 @@ when `dialerProxy` is set `happyEyeballs` is not applied, and only a random IP w ```json "happyEyeballs": { "tryDelayMs": 250, - "prioritizeIPv6": false, + "prioritizeIPv6": false, + "interleave": 1, "maxConcurrentTry": 4, - "interleave": 1 } ``` @@ -684,14 +684,20 @@ when `dialerProxy` is set `happyEyeballs` is not applied, and only a random IP w delay time between each attempt in millisecond, RFC-8305 recommend `250`, default is `0`. (if it is `0`, happy-eyeballs is disabled) -> `interleave`: number - - indicate "First Address Family count" in RFC-8305, default is 1. - > `prioritizeIPv6`: bool indicate "First Address Family" in RFC-8305, default is false(= prioritizeIPv4) +> `interleave`: number + + indicate "First Address Family count" in RFC-8305, default is 1. + +for example suppose our IP-list is [ip4-1, ip4-2, ip4-3, ip4-4, ip6-1, ip6-2, ip6-3, ip6-4] +when interleave is 1 and prioritizeIPv6 is false, the sorted-ip-list is: +[ip4-1, ip6-1, ip4-2, ip6-2, ip4-3, ip6-3, ip4-4, ip6-4] +and when for example interleave is 2 and prioritizeIPv6 is true: +[ip6-1, ip6-2, ip4-1, ip4-2, ip6-3, ip6-4, ip4-3, ip4-4] + > `maxConcurrentTry`: number maximum concurrent attempt (this is only maximum and in most cases our concurrent attempts is less, unless all connection fail to connect) also we can always have a maximum of concurrent-attempt as many IPs as we have, and this option is useful when the number of IPs is too high, and we want to control the number of concurrent-attempts, default is 4. if it is 0, happy-eyeballs is disabled. From 15cd824e6e1cd4adfa6b9fd928a0d0797d9a3599 Mon Sep 17 00:00:00 2001 From: patterniha <71074308+patterniha@users.noreply.github.com> Date: Thu, 26 Jun 2025 13:42:11 +0330 Subject: [PATCH 4/7] Update transport.md --- docs/en/config/transport.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/config/transport.md b/docs/en/config/transport.md index c6331af576..0ee143525b 100644 --- a/docs/en/config/transport.md +++ b/docs/en/config/transport.md @@ -666,7 +666,7 @@ in `AsIs` domainStrategy, built-in golang happyEyeballs is applied(currently it ::: tip -when `dialerProxy` is set `happyEyeballs` is not applied, and only a random IP will replace the domain. +when `dialerProxy` is set, `happyEyeballs` is not applied, and only a random IP will replace the domain. ::: From 3a89b433137ceb30a90a77dc75127adca77084c3 Mon Sep 17 00:00:00 2001 From: patterniha <71074308+patterniha@users.noreply.github.com> Date: Thu, 26 Jun 2025 15:07:19 +0330 Subject: [PATCH 5/7] Update transport.md --- docs/en/config/transport.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/en/config/transport.md b/docs/en/config/transport.md index 0ee143525b..39b04890d0 100644 --- a/docs/en/config/transport.md +++ b/docs/en/config/transport.md @@ -511,7 +511,9 @@ Transparent proxy requires Root or `CAP\_NET\_ADMIN` permission. When `followRedirect` is set to `true` in [Dokodemo-door](./inbounds/dokodemo.md), and `tproxy` in the Sockopt settings is empty, the value of `tproxy` in the Sockopt settings will be set to `"redirect"`. ::: -> `domainStrategy`: "AsIs" | "UseIP" | "UseIPv4" | "UseIPv6" +> `domainStrategy`: "AsIs" +"UseIP" | "UseIPv6v4" | "UseIPv6" | "UseIPv4v6" | "UseIPv4" +"ForceIP" | "ForceIPv6v4" | "ForceIPv6" | "ForceIPv4v6" | "ForceIPv4" In previous versions, when Xray attempted to establish a system connection using a domain name, the resolution of the domain name was completed by the system and not controlled by Xray. This led to issues such as the inability to resolve domain names in non-standard Linux environments. To solve this problem, Xray 1.3.1 introduced Freedom's `domainStrategy` into Sockopt. @@ -519,6 +521,9 @@ When the target address is a domain name, the corresponding value is configured, - `"AsIs"`: Resolve the IP address using the system DNS server and connect to the domain name. - `"UseIP"`, `"UseIPv4"`, and `"UseIPv6"`: Resolve the IP address using the [built-in DNS server](./dns.md) and connect to the IP address directly. +- "IPv4" means that you are trying to connect using only IPv4, "IPv4v6" means that you are trying to connect using either IPv4 or IPv6, but for dual-stack domain names, IPv4 is used. (The same applies to the v4v6 switch, so I won't go into details.) +- When using "Use" the option beginning with , if the resolution result does not meet the requirements (for example, the domain name only has IPv4 resolution results but UseIPv6 is used), it will fall back to AsIs. +- When using "Force" an option beginning with , if the parsing result does not meet the requirements, the connection cannot be established. The default value is `"AsIs"`. From b057cd314009308dd3aa5c4cab3564920e5be6f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A3=8E=E6=89=87=E6=BB=91=E7=BF=94=E7=BF=BC?= Date: Thu, 26 Jun 2025 20:04:23 +0800 Subject: [PATCH 6/7] Update transport.md --- docs/config/transport.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/docs/config/transport.md b/docs/config/transport.md index 78eec8a604..17f43f5644 100644 --- a/docs/config/transport.md +++ b/docs/config/transport.md @@ -26,6 +26,7 @@ "tcpFastOpen": false, "tproxy": "off", "domainStrategy": "AsIs", + "happyEyeballs": {}, "dialerProxy": "", "acceptProxyProtocol": false, "tcpKeepAliveInterval": 0, @@ -816,3 +817,39 @@ PS: 如果有正常上网的域名流量被 AsIs 的 freedom 出站送过来, 要设置的选项值,此处示例为设置为bbr. 当 type 指定为 int 时需要使用十进制数字。 + + +> `happyEyeballs`: {} + +RFC-8305 实现的 happyEyeballs 仅适用于 TCP, 当目标为域名时对它们竞速并选择第一个成功的返回,当 `domainStrategy` 被设置为 `UseIP`/`ForceIP` (包括它们的v4/v6/v4v6版本,但这会使可用的IP列表被缩减到仅剩v4或v6,不推荐这么用) + +::: warning +使用这个功能时不要使用 `Freedom` 出站的 `domainStrategy`, 这会导致 `Sockopt` 只能看到被替换完毕的 IP. +::: + +```json +"happyEyeballs": { + "tryDelayMs": 250, + "prioritizeIPv6": false, + "interleave": 1, + "maxConcurrentTry": 4, +} +``` + +> `tryDelayMs`: number + +每个竞速请求发起时间的间隔,单位毫秒,默认为0(代表禁用该功能),推荐值为 250. + +> `prioritizeIPv6`: bool + +排序 IP 时首个 IP 的类型,默认为 false (即 IPv4 会被排在第一个) + +> `interleave`: number + +RFC-8305 中的 "First Address Family count", 默认值为 1. 它定义了对不同IP版本进行排序时的交错行为。 + +比如等待 dial 的 IP 队列会被排序为 46464646 (设置为1) 44664466 (设置为2) (6 代表 IPv6 地址, 4 代表 IPv4 地址). + +> `maxConcurrentTry`: number + +最大并发数量,用于防止解析出的IP过多且均未成功时候核心也对这些IP产生大量连接。默认为4, 设置为0代表禁用 happyEyeballs. From 2b7ae341e1a8ed76c956773da2419b95c3813f77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A3=8E=E6=89=87=E6=BB=91=E7=BF=94=E7=BF=BC?= Date: Thu, 26 Jun 2025 20:07:06 +0800 Subject: [PATCH 7/7] Update transport.md --- docs/en/config/transport.md | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/docs/en/config/transport.md b/docs/en/config/transport.md index 39b04890d0..1ffb9abad6 100644 --- a/docs/en/config/transport.md +++ b/docs/en/config/transport.md @@ -663,18 +663,6 @@ in `freedom` settings when you set `domainStrategy` to `UseIP`/`ForceIP` just a ::: -::: tip - -in `AsIs` domainStrategy, built-in golang happyEyeballs is applied(currently it is RFC-6555) - -::: - -::: tip - -when `dialerProxy` is set, `happyEyeballs` is not applied, and only a random IP will replace the domain. - -::: - ```json "happyEyeballs": { "tryDelayMs": 250,