Skip to content

Direct/Freedom outbound: Better Compatibility#6058

Open
Meo597 wants to merge 12 commits into
mainfrom
finalrules
Open

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

Conversation

@Meo597

@Meo597 Meo597 commented May 2, 2026

Copy link
Copy Markdown
Collaborator

按照下面的讨论,现在是这样的:

freedom.domainStrategy 已经干掉了,自动兼容旧配置并提醒用户

  • 有 proxySettings.tag 时,且 targetStrategy 为 AsIs 则旧配置自动覆写为 targetStrategy
  • 旧配置默认覆写为 sockopt.domainStrategy

freedom 新增选项 privacyGuard,它有三种状态:未设置、显式 true、显式 false

  • 未设置时,盾尽量开启,除非 targetStrategy && sockopt.domainStrategy 是非 AsIs
    翻译下就是“用户有策略听用户的,否则 v4 优先”
  • 显式 true 时,一旦 targetStrategy + sockopt.domainStrategy 不是 v4 优先,会警告并强制覆写为 AsIs + UseIPv4v6
    翻译下就是“一旦显式设置,必须保证 v4 优先”
  • 显式 false 不覆写,因此 sockopt.domainStrategy 的 AsIs 可以生效

finalRules 现在不会覆写 IP,而且 freedom 也不允许覆写 IP,都是偷看 sockopt 策略,解析出来判所有 IP

  • 如果是偷看时解析失败,dial 解析成功则会漏一个 SYN
  • 如果有 dialerProxy 之类的东西,只能尽力而为,因为就算改写成 IP 他们也可以嗅探了再重新解析,毫无意义

意思是在 freedom 真的是最终出站时绝对有效,但若还有 sockopt.dialerProxy、proxySettings.tagsockopt.addressPortStrategy 时则尽力而为

UDP domain 有更好的兼容性

  • 不再偏好 v4,无论用户设了哪个 strategy 都会和 TCP 行为完全一致

proxySettings 整个干掉了

  • 历史遗留链式代理,现在有兼容性更好的 dialerProxy

freedom 不兼容 sockopt.addressPortStrategy

  • 降低复杂度,也没必要兼容它,这是不正确的配置

@Meo597

This comment was marked as outdated.

@RPRX

RPRX commented May 2, 2026

Copy link
Copy Markdown
Member

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

@RPRX

RPRX commented May 2, 2026

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

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

@Meo597

Meo597 commented May 2, 2026

Copy link
Copy Markdown
Collaborator Author

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

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

之前说了一大堆 0 人在意

@Meo597

Meo597 commented May 2, 2026

Copy link
Copy Markdown
Collaborator Author

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

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

@RPRX

RPRX commented May 2, 2026

Copy link
Copy Markdown
Member

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

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

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

@Meo597

Meo597 commented May 2, 2026

Copy link
Copy Markdown
Collaborator Author

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

@RPRX

RPRX commented May 2, 2026

Copy link
Copy Markdown
Member

你开个 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

RPRX commented May 2, 2026

Copy link
Copy Markdown
Member

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

@Meo597

Meo597 commented May 2, 2026

Copy link
Copy Markdown
Collaborator Author

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

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

@RPRX

RPRX commented May 2, 2026

Copy link
Copy Markdown
Member

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

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

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

@Meo597

Meo597 commented May 2, 2026

Copy link
Copy Markdown
Collaborator Author

ok 明白了

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

@RPRX

RPRX commented May 2, 2026

Copy link
Copy Markdown
Member

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

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

@RPRX

RPRX commented May 2, 2026

Copy link
Copy Markdown
Member

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

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

@Meo597

Meo597 commented May 3, 2026

Copy link
Copy Markdown
Collaborator Author

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

@patterniha

patterniha commented May 4, 2026

Copy link
Copy Markdown
Collaborator

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

Meo597 commented May 4, 2026

Copy link
Copy Markdown
Collaborator Author

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

@patterniha

patterniha commented May 4, 2026

Copy link
Copy Markdown
Collaborator

@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

Meo597 commented May 4, 2026

Copy link
Copy Markdown
Collaborator Author

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

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

@patterniha

patterniha commented May 4, 2026

Copy link
Copy Markdown
Collaborator

???
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

Meo597 commented May 4, 2026

Copy link
Copy Markdown
Collaborator Author

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

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

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

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

@patterniha

patterniha commented May 4, 2026

Copy link
Copy Markdown
Collaborator

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

Meo597 commented May 4, 2026

Copy link
Copy Markdown
Collaborator Author

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

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

@Meo597

Meo597 commented May 4, 2026

Copy link
Copy Markdown
Collaborator Author

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

@Meo597

Meo597 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

target 发生在 freedom 之前,没有被偷看
感觉没必要特别去写代码屏蔽 target + freedom 的组合

写起来比目前隐私盾或许还要多几行

@RPRX

RPRX commented Jul 8, 2026

Copy link
Copy Markdown
Member

发生在 freedom 之前吗那没事了

我现在看下你那个新加的选项

@Meo597

Meo597 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

我又看了下

忘了。。。为了修复 UDPDomain
freedom 还是要看 targetStrategy 算不上偷

怎么说,是 break 掉 freedom + targetStrategy 并且

前段时间已经有 StreamSettingsFromContext 给你读了 不用改造handler递出来了


还是保持现状?

@Fangliding

Copy link
Copy Markdown
Member

本来有一个freedom的domainstrategy 然后patterniha加targetstrategy的时候你说反正这玩意和freedom的domainstrategy的功能一样 要他给freedom的domainstrategy加了个同名的别名
我说了别乱加别名吧 一拍脑袋的别名到头来自己都搞糊涂了
#5006 (comment)

@RPRX

RPRX commented Jul 8, 2026

Copy link
Copy Markdown
Member

@Fangliding 我们说的是 outbound 那个 targetStrategy,你先别添乱了,绝大多数别名/重命名都是更合理的,反对无效

@Meo597 那还是 freedom 禁止配 targetStartegy,另外你那个选项别加了,sockopt ds 默认值都从 asis 改成 usev4v6 吧

@Meo597

Meo597 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

那个 privacyGuard 主要是你怕面板、GUI 们默认都显式给 AsIs

而且 sockopt.ds 默认 AsIs 好处是 go dial 解析策略会优先拨 v6,双栈服务器 v6 据说墙低

@Fangliding

This comment was marked as outdated.

@RPRX

RPRX commented Jul 8, 2026

Copy link
Copy Markdown
Member

就是说不光 freedom,所有都是 v4 优先,包括代理协议出站,想要 asis 或 v6 优先/强制的可以自己去设置

没几个 GUI 去设默认 sockopt ds asis 的,所以还好,和 freedom 被删掉那个不一样(所以这个也别兼容了吧,直接 ignore)

v6 墙是低了但更容易实名到个人,都不用去调运营商数据,不妥,想要 v6 过墙的自己改设置吧,本来就有设置吧

另外你 PR 描述中删除线的内容都过时了,直接删掉别留着

@Fangliding 因为上文已经决定把 freedom 的 ds 干掉了所以我们都没在想这个,两个名都被扬了,别纠结了,刷屏折叠一下

@Fangliding

Copy link
Copy Markdown
Member

sockopt.Domainstrategy乱改use有的配置要炸回环的 假如有人就配了个vmess出站 里面是域名 然后内置dns配了个1.1.1.1 再正常不过的配置 本来出站正常走asis走系统DNS 内置DNS也走这个出站出去 sockopt.Domainstrategy 改默认use这个1.1.1.1没地方出去了回环了

@RPRX

RPRX commented Jul 8, 2026

Copy link
Copy Markdown
Member

因为他现在要加个选项就有点没必要了,就只是因为默认值是 asis,炸的不多就可以接受,毕竟 GUI 基本都没你说的这么复杂

@Fangliding

Fangliding commented Jul 8, 2026

Copy link
Copy Markdown
Member

任何一个GUI只要填了内置DNS就会有这个问题 甚至不是GUI 手写一样遇到 这可不是少数

@Meo597

Meo597 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

删掉 privacyGuard
outbound.targetStrategy + freedom 可用,且默认 UseIPv4v6?
这样影响也小,还给用户使用 v4 指明了方向

或者干脆默认全 AsIs 不再帮用户默认 v4

@Fangliding

This comment was marked as duplicate.

@RPRX

RPRX commented Jul 8, 2026

Copy link
Copy Markdown
Member

@Fangliding 刚刚没仔细看,似乎是有这个问题,我再想想

@Meo597 “freedom 禁止配 targetStartegy”


@Fangliding 可以给链接,不要刷屏

@RPRX

RPRX commented Jul 8, 2026

Copy link
Copy Markdown
Member

可以这样,sockopt ds 不填任何东西时,用系统 DNS 解析出来 IP 并优先 v4,有 dialerProxy 时就不管了直接传域名过去

@Meo597

Meo597 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

“freedom 禁止配 targetStartegy”

删掉 privacyGuard 并且 sockopt.ds 不能全改默认值的情况下
freedom 默认 v4 这个需求还要不

要的话就只能是 infra 那边 freedom 遇到 sockopt 并且 asis 强制改写为 useipv4v6

@Meo597

Meo597 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

可以这样,sockopt ds 不填任何东西时,用系统 DNS 解析出来 IP 并优先 v4,有 dialerProxy 时就不管了直接传域名过去

改动面巨多无比,ds 不是个普通的变量,没法简单的在 core 里判断 "" 还是 asis

@Meo597

Meo597 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

sockopt 遇到 freedom 在 infra 层面强行改写为 useipv4v6 是最直观简单的

@RPRX

RPRX commented Jul 8, 2026

Copy link
Copy Markdown
Member

@Meo597 改动哪里多了,分配个新的标号 internet.DomainStrategy_OS_IP46 不就行了,注意 TUN 那个别回环

@RPRX

RPRX commented Jul 8, 2026

Copy link
Copy Markdown
Member

矛盾是 asis 不能选 4/6,而其它的都走内置 DNS、容易回环,还是功能上不够方便,以后可以加些选择,现在先随便给个标号

@Meo597

Meo597 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

ok

@Meo597

Meo597 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

对于 targetStrategy 来说 os_ip46 是个废选项,有点不美观

@RPRX

RPRX commented Jul 8, 2026

Copy link
Copy Markdown
Member

那本来就不太能支持啊,不然 DNS 泄漏,况且对于内置 DNS 的 queryStrategy 来说废选项岂不是更多

纠结那么多干嘛,本来没说让你加个“用户可选参数”的,实在纠结的话就把 os_ip4 os_ip6 os_ip64 全加上、写文档里

这个和 Go 的 dial 应该是能拿到相同的解析结果吧,那也不用回退 asis 了,没查到的话 Go 内置库也查不到

一定注意一是 TUN 别回环(Go 自己查的会吗?),二是 dialerProxy 时回退 asis,先默认这样吧不然又要加个选项

@Meo597

Meo597 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

dialerProxy 回退目的防泄漏呗,那么 UDPDomain 那边原本其实一直泄露的

udpAddr, err := net.ResolveUDPAddr("udp", b.UDP.NetAddr())

@RPRX

RPRX commented Jul 8, 2026

Copy link
Copy Markdown
Member

主要是 dialerProxy 的话交给远端查 DNS 更好,这个解析是必要的吗,现在偷看 sockopt 了,要不你把这个行为改了吧

@RPRX

RPRX commented Jul 8, 2026

Copy link
Copy Markdown
Member

话说有点想把 finalRules 移到 sockopt,但感觉暂时没必要,sockopt 也没写过这么复杂的东西,先把 Freedom 这个弄成熟吧

@Meo597

Meo597 commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator Author

主要是 dialerProxy 的话交给远端查 DNS 更好,这个解析是必要的吗,现在偷看 sockopt 了,要不你把这个行为改了吧

这里以前应该完全没考虑 freedom dialerProxy 的事,在 core 体系里最终有效出口只有 wg 和 freedom
我觉得可以直接 WriteDomain 不会出事,别的项目给 freedom 自己搞了奇奇怪怪的 dialerProxy 他应该负责解析
没毛病吧

@Meo597

Meo597 commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator Author

话说刚发现 wg 那边没有 UDPDomain 的缓存

@RPRX

RPRX commented Jul 9, 2026

Copy link
Copy Markdown
Member

是没有,我早说过了,先别管那个,先把这个 PR 搞好

@Meo597

Meo597 commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator Author

在弄了,估计要两天
两个月过去上下文丢的有点多,我得回忆一下

还有 dialerProxy 以前也没好好处理,较真起来泄露的有点多

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.

freedom 出站中 sockopt 的部分设定失效

5 participants