Skip to content

Direct/Freedom outbound: Better Compatibility#6058

Open
Meo597 wants to merge 5 commits into
mainfrom
finalrules
Open

Direct/Freedom outbound: Better Compatibility#6058
Meo597 wants to merge 5 commits into
mainfrom
finalrules

Conversation

@Meo597
Copy link
Copy Markdown
Collaborator

@Meo597 Meo597 commented May 2, 2026

  1. AsIs 时偷看 sockopt 把所有 IP 都拉出来判定一遍,但不改写 dest
    这样可以让 UDPDomain 的 domainStrategy 跟 happyeyeballs 一致
    这样也不用改写目标了,服务端的 happyeyeballs 也可以启用了
  2. domainStrategy 的一个性能微优化,benchmark 几乎不可能有区别,但定长是个好习惯
  3. UDPDomain 无脑偏好 v4 问题
  4. Sockopt: Add addressPortStrategy (query SRV or TXT) #4416 的 SRV/TXT 也可以兼容,但这里是 dial 后封锁
  5. 有 dialerProxy/proxySettings 时跳过 finalRules 虽然我觉得不会有人这么无聊这么配应该
  6. UDP 发包那块 b.UDP == nil 时会漏掉过滤,给补上了
    不清楚什么情况会走到这里,但我看本来就有原样发出去的行为
    Direct/Freedom outbound: Add blockDelay to finalRules (30~90s by default) #6060 已在 dial 时黑洞了,无需再逐包过滤
  7. 有 finalRules 时若解析失败尽可能重试,最后再 dial 后兜底

@Meo597
Copy link
Copy Markdown
Collaborator Author

Meo597 commented May 2, 2026

本来想的是把 finalrules 放到 ctx 在 dialer 取出来再拦
试了下污染的地方太多了
这些地方没摸过怕动炸了

所以做成了偷看 sockopt
当 asis 时把所有 ip 拉出来判黑
如果 dial 时解析刷新了,事后也有补救

缺点大概就是上面的 4
以及某域名突然在国内设节点,并且恰好在那个窗口期 DNS 缓存过期了

@RPRX
Copy link
Copy Markdown
Member

RPRX commented May 2, 2026

必须狠狠教育一下了,发版在即,不要把尚需大量讨论的新变动和 bug fix 放一个 PR 里,不然怎么发版,甚至还是个 draft

@RPRX
Copy link
Copy Markdown
Member

RPRX commented May 2, 2026

6. UDP 发包那块 `b.UDP == nil` 时会漏掉过滤,给补上了
   不清楚什么情况会走到这里,但我看本来就有原样发出去的行为

这种情况有几种可能,比如 VLESS 没走 XUDP,就不会赋值 b.UDP,之前 ipsBlocked 是没问题的,现在 dial 那里放过了 UDP

@Meo597
Copy link
Copy Markdown
Collaborator Author

Meo597 commented May 2, 2026

怕耽误发版标记为 draft
这个 PR 主要目的是恢复一些 finalrules 破坏掉的的兼容性
凭感觉写的我还没测

#6027 (comment)
#6027 (comment)
#6027 (comment)
#6027 (comment)
#6027 (comment)
#6027 (comment)

之前说了一大堆 0 人在意

@Meo597
Copy link
Copy Markdown
Collaborator Author

Meo597 commented May 2, 2026

主要是想兼容老哥的 happyeyeballs
虽然我不用,但看着难受。。。

这些边角的 BUG 早就存在了
没人反馈过 XTLS/Xray-docs-next#781 (comment)

@RPRX
Copy link
Copy Markdown
Member

RPRX commented May 2, 2026

还有其它一些情况会导致序号 6,但我看了下代码倒是又发现了别的问题,如果 UDP 那里

if c, ok := iConn.(*internet.PacketConnWrapper); ok {

这个断言失败,就不会走到自定义的 PacketReader/Writer,而是 buf.PacketReader/buf.SequentialWriter,绕过了过滤逻辑

@Meo597
Copy link
Copy Markdown
Collaborator Author

Meo597 commented May 2, 2026

那再包一层,我开个 PR 单独修这几项呗

@RPRX
Copy link
Copy Markdown
Member

RPRX commented May 2, 2026

你开个 PR,这样吧:

  1. 这种服务端的封锁,为了避免客户端重试 dial TCP 或发包 UDP,只要第一个 dest 命中 block,随机 30-90s 后关闭连接
    finalRules 加个 blockDelay 允许配置随机多少秒,Block/Blackhole outbound: Better blocking UDP #6057 要不要改以后再讨论
  2. 针对刚刚说的 Direct/Freedom outbound: Better Compatibility #6058 (comment) 再包一层
  3. 想到除了 Direct/Freedom 出站,DNS 出站也可能把 DNS 漏到 CN IP,以后再说吧,毕竟那个默认是 hijack

@RPRX
Copy link
Copy Markdown
Member

RPRX commented May 2, 2026

#6058 (comment) 基本上只是因为 NG 自定义 dialer,然后又出现了域名的问题,还是先不管它吧,你先把上面的 1 给 PR 了

@Meo597
Copy link
Copy Markdown
Collaborator Author

Meo597 commented May 2, 2026

blockDelay 感觉又堆砌了个选项进来
要不先给默认了缓解下这个问题,我感觉这块以后还会长成现在这个 PR 的样子

毕竟这些 feature 理论上不该冲突,只是得益于屎山代码。。。

@RPRX
Copy link
Copy Markdown
Member

RPRX commented May 2, 2026

并非“理论上不该冲突”,这里的一些东西它理论上就是冲突的,因为 finalRules 要求在 freedom 这步就解析出 IP,这必然要跳过 sockopt 的 domainStrategy 和 happyEyeballs;就算这俩能读取,你要配置 dialerProxy 的话那还是控制不了它最终实际上 dial 到哪,此时 finalRules 可能根本就没意义;NG 自定义 dialer 可能有自定义域名解析策略等,这就更不该提前解析出 IP 了

并非“屎山”而是可能的用法太多了,我的意思是这个特性目前只针对服务端,先不考虑客户端的那些情况

blockDelay 并非堆砌选项而是服务端 block 就该有的东西,不然客户端 dial TCP 重试五次,GFW 看到五个立马关闭的连接

@Meo597
Copy link
Copy Markdown
Collaborator Author

Meo597 commented May 2, 2026

ok 明白了

漏掉了 TCP 那个客户端行为在墙眼里是什么样

@RPRX
Copy link
Copy Markdown
Member

RPRX commented May 2, 2026

漏掉了 TCP 那个客户端行为在墙眼里是什么样

那取决于被代理的应用了,代理层 dial 是成功了不会 retry,但应用层可能发现一发数据就被关连接,所以可能会重试几次

@RPRX
Copy link
Copy Markdown
Member

RPRX commented May 2, 2026

根据 #6060 更新下文档然后 rebase 一下,剩下的讨论在这里进行

其实也没那么复杂,#6058 (comment) 都列举清楚了,区分服务端/客户端后就清晰很多

@Meo597
Copy link
Copy Markdown
Collaborator Author

Meo597 commented May 3, 2026

文档改好了,UDP 断言失败不会逐包过滤暂时没提

@patterniha
Copy link
Copy Markdown
Collaborator

patterniha commented May 4, 2026

I still don't know why we need multi-domain-udp-cone, if I were the decision maker, I would remove multi-domain-udp-cone-support and also remove freedom-domainStrategy (which coexistence with sockopt-domainStrategy causes confusion), then move finalRules-code to dialer and enable xray-happyEyeballs by default and use "localhost-dns" for "AsIs", then all the problems would be solved!

@Meo597
Copy link
Copy Markdown
Collaborator Author

Meo597 commented May 4, 2026

只有 freedom 才需要最终过滤
目的是控制用户出站流量,而非所有连接

@patterniha
Copy link
Copy Markdown
Collaborator

patterniha commented May 4, 2026

@Meo597 @RPRX

addrs, err := net.DefaultResolver.LookupIPAddr(ctx, dialDest.Address.Domain())
if err != nil {
errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", dialDest.Address.Domain())
} else if len(addrs) > 0 {
if addr := net.IPAddress(addrs[dice.Roll(len(addrs))].IP); addr != nil {
dialDest.Address = addr
errors.LogInfo(ctx, "dialing to ", dialDest)
}
}

this code disable both xray and go happyEyeballs, also net.DefaultResolver.LookupIPAddr returns both v4 and v6 ips (even our server has ipv4 only),

so it is possible that an ipv6 is selected but our server has ipv4 only.

so we should filter IPs before we choose one at random (use "queryStrategy": "UseSystem" code here)

///

but it is still possible that our server has an inactive ipv6 interface or one ip type is disabled at target-side, so disabling happyEyeballs is not good idea at all.

so finalRules should filter ips, and then pass the filtered-ips to xray-happyEyeballs, and we should also enable xray-happyEyeballs by default.

@patterniha
Copy link
Copy Markdown
Collaborator

只有 freedom 才需要最终过滤 目的是控制用户出站流量,而非所有连接

if outboundName == "freedom" && dest.Network == net.Network_UDP && origTargetAddr != nil && src == nil {

we can check outboundName == "freedom" in dialer, i also used this for another problem.

@Meo597
Copy link
Copy Markdown
Collaborator Author

Meo597 commented May 4, 2026

为了让你的 udpdomain 和 happyeyeballs 行为一致
就必须得在 freedom 偷看 sockopt
跟是否删掉 freedom.domainstrategy 无关

既然已经偷看了,那就没必要改 dialer 让能传递多个 dest 下去

@patterniha
Copy link
Copy Markdown
Collaborator

patterniha commented May 4, 2026

???
you select ipv6 for ipv4-only-server, this is critical problem and should be solve quickly.

you can prioritize ipv4 when selecting ip, but most of the time ipv6 has better performance and it is not future-proof.

I don't understand your resistance to using xray-happyEyeballs (this is not about the properties of happyEyeballs-v2, this is about the essential properties of happyEyeballs-v1)

///

I still think we should remove multiple-domain-udp-cone support, anyway we can keep it and have duplicate finalRules-code in freedom (or keep finalRules-code in freedom and just pass the filtered-ips via ctx)

@Meo597
Copy link
Copy Markdown
Collaborator Author

Meo597 commented May 4, 2026

I still think we should remove multiple-domain-udp-cone support

不能因为你的两个功能互相打架就把其中之一删掉

finalrules udpdomain 都和 happyeyeballs 冲突
现在不就是为它擦屁股吗
不宜做更广泛的改动

以及 ipv6 跨国路由绝大多数情况下都比 ipv4 烂

@patterniha
Copy link
Copy Markdown
Collaborator

patterniha commented May 4, 2026

finalRules should act as a filter for tcp and then pass the filtered-ips via ctx to dialer-happyEyeballs, otherwise choosing only one ipv4 will definitely weaken the performance of Xray-core.
@RPRX i can open a simple PR for that, anyway, even if you don't agree, you can just prioritize ipv4 when selecting ip for finalRules and release the new version, this is important problem and should be fixed soon.

@Meo597
Copy link
Copy Markdown
Collaborator Author

Meo597 commented May 4, 2026

首先你这玩意也就客户端用
其次我不提根本没人在意这个兼容性

就别为这个东西再大肆破坏现有结构了

@Meo597
Copy link
Copy Markdown
Collaborator Author

Meo597 commented May 4, 2026

再多 thumbs down 你的 udpdomain 还是和 happyeyeballs 打架
自己的 PR 应该自己负责,至少不应该冲突

@patterniha
Copy link
Copy Markdown
Collaborator

happyEyeballs-v2 may be more important for client-side, but happyEyeballs-v1 is essential for both sides.

currently many iran websites return both ipv4 and ipv6 for dns, but their ipv6 is not accessible from outside

@patterniha
Copy link
Copy Markdown
Collaborator

No matter how many thumbs you add, your UDP domain will still be fighting with happyeyeballs. You should be responsible for your own PR, and at the very least, there shouldn't be any conflict.

There is no conflict happyEyeballs is for tcp and udp-domains is for udp!

@Meo597
Copy link
Copy Markdown
Collaborator Author

Meo597 commented May 4, 2026

freedom 和 sockopt 的 domainstrategy 导致 udpdomain 和 happyeyeballs 的解析行为不一致
不想陷入无意义的争论

@patterniha
Copy link
Copy Markdown
Collaborator

This conflict is between freedom-domainStrategy and sockopt-domainStrategy, not between happyEyeballs and udpdomains, we can simply use sockopt-domainStrategy for udpdmains with some changes in infra.

Pointless arguments ...

@Meo597
Copy link
Copy Markdown
Collaborator Author

Meo597 commented May 4, 2026

freedom.domainstrategy asis
udp 走 go 解析

要用你的 happyeyeballs 必须得 sockopt 设为非 asis

你如果没明白可以去看文档,当时发现你这个 bug
怎么写文档都想了半天

@Meo597 Meo597 marked this pull request as ready for review May 4, 2026 07:20
@patterniha
Copy link
Copy Markdown
Collaborator

freedom.domainstrategy asis udp 走 go 解析

要用你的 happyeyeballs 必须得 sockopt 设为非 asis

你如果没明白可以去看文档,当时发现你这个 bug 怎么写文档都想了半天

??? for AsIs we had go-happyEyeballs, so usually there is no need for my happyEyeballs.

I write happyEyeballs because i need build-in-dns but choosing one random ip didn't meet my needs (Iranian society).

So it is basically for ForceIP-domainStrategy (it is also v2, which has many advantages and when we need those advantages we could simply use build-in-dns if we want)

@Meo597
Copy link
Copy Markdown
Collaborator Author

Meo597 commented May 4, 2026

因此你的快乐眼球会让你的 UDPDomain 不快乐,这是可接受的
finalrules 破坏快乐眼球,绝对不行

@patterniha
Copy link
Copy Markdown
Collaborator

my happyEyeballs have nothing to do with this problem, you (probably) chose ipv6 for ipv4-only-server and disabled go-happyEyeballs, what does this have to do with my happyEyeballs, which is disabled by default?!!

ha...

@Fangliding
Copy link
Copy Markdown
Member

本质把封在dialer里的史复制了一坨进freedom
dialer要域名做决策 出站要ip做决策 出站把目标弄成ip 那dialer拿不到域名了 dialer没域名干不了活 标一下不兼容不干 觉得不舒服于是破坏封装把本来dialer要看的东西拿出来自己拿出来弄一遍 弄那么大一圈目的是为了防止路由没发现属于cn的请求漏一个syn去cn

@Fangliding
Copy link
Copy Markdown
Member

干脆让freedom把阻塞请求扔 session.Outbound 里算了 里面弄个finalrule matcher云云的让dialer去弄 下面happyeyeball或者srv做解析的时候都能看到 freedom顶多留个udp过滤

@Meo597
Copy link
Copy Markdown
Collaborator Author

Meo597 commented May 4, 2026

把 finalrules 塞 session 也没见得好多少
因为 freedom 仍然要逐包过滤 udp
而且那样 udpdomain 问题还是无解,非得偷看 sockopt 不可

不大规模重构前提下,为了功能绝对正确,不增加用户心智负担,能糊进去就行了
追求不破坏抽象层的话,怎么写都是错

代码是给人用的,封装是给开发者用的,过度追求不破坏封装在我看本末倒置了
最后还得文档写一大堆恶心用户
而且这时候为什么不反思本来设计的合不合理

udpdomain 也可以完全不管,文档标一下让有需求的用户在路由搞俩 freedom,tcp udp 各一个就完事了

@patterniha
Copy link
Copy Markdown
Collaborator

it seems prefect.

@Meo597
Copy link
Copy Markdown
Collaborator Author

Meo597 commented May 6, 2026

thx

@patterniha
Copy link
Copy Markdown
Collaborator

patterniha commented May 7, 2026

@Meo597

I couldn't convince @RPRX to use Xray-happyEyeballs for finalRules in the end.

so rebase this PR base on d9fa5b4.

this is also important PR because it solve udpDomain-happyEyeballs-conflict and some other problems.

@Meo597
Copy link
Copy Markdown
Collaborator Author

Meo597 commented May 7, 2026

回头等讨论出结果我再 rebase

@KobeArthurScofield
Copy link
Copy Markdown
Contributor

现在是 Direct/Freedom 除了直接转发之外还干了路由和 Block/Blackhole 的活

这样的话,不如:

  1. 把 Direct/Freedom 的 DomainStrategy 去掉,进来是什么传给 dialer 就是什么,不做额外覆写。就这个出站有两个地方写 DomainStrategy 本来就是个令人迷惑烂主意,一不小心就有可能写出前后矛盾的配置,而且 dialer 这边除了 DomainStrategy 还有 HappyEyeballv2。(它不像 WireGuard 要求传给下一个节点的时候必须是 IP 必须做单独的 DomainStrategy)
  2. 初始化的时候偷看 SockOpt 的 DomainStrategy,然后根据情况决定怎么在 FinalRules 查询 IP(用 Go 自己查询还是用内置 DNS 服务器);
  3. 查出来命中禁止 IP CIDR 就导向给 Block/Blackhole 或者就断开,什么都不要传给 dialer;要是查询出问题尽量重试,重试几次不行 就看平常是怎么兜底的 看怎么做更合理。

Direct/Freedom 能写两个地方的 DomainStrategy 这个迷惑设计没能在上次统一 DomainStrategy 的时候处理掉也算是问题的来源

@Meo597
Copy link
Copy Markdown
Collaborator Author

Meo597 commented May 7, 2026

@RPRX 想要 DomainStrategy AsIs 服务器端时 v4 优先

是不是单给 freedom 开个选项好点。比如 privacy true 时覆盖 sockopt 使服务端、客户端有不同的行为

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants