Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add query srv record for server endpoint redirection #4416

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

j3l11234
Copy link

@j3l11234 j3l11234 commented Feb 19, 2025

使用场景:移动宽带使用lucky,把xray的端口通过stun暴露出去,但是暴露的端口是不稳定的会变化的,需要客户端每次都改ip和端口。

使用步骤:
1.lucky使用webhook把最新的端口放在域名的srv记录中
2. 在xray客户端链接的时候,通过配置判断是否解析srv记录,解析后再反过来修改端口号。

{
 "outbounds": [
  {
    "tag": "proxy",
    "protocol": "vless",
    "settings": {
      "vnext": [
        {
          "address": "_txt_.***.com",
          "port": 8443

        }
      ]
    },
    "streamSettings": {
      "sockopt": {
        "destinationStrategy": "TxtPortAndAddress"
      }
    }
  }
}
{
 "outbounds": [
  {
    "tag": "proxy",
    "protocol": "vless",
    "settings": {
      "vnext": [
        {
          "address": "_xray._tcp.***.com",
          "port": 8443

        }
      ]
    },
    "streamSettings": {
      "sockopt": {
        "destinationStrategy": "SrvPortAndAddress"
      }
    }
  }
}

1739983175603
1740025011041

@Fangliding
Copy link
Member

Fangliding commented Feb 19, 2025

首先txt记录端口好像不是什么标准行为 用也是用srv
之前跟人讨论过这个问题 后来不了了之了 一个问题是内置DNS面向的是IP 并不支持其他类型解析 以及处理缓存问题(直接用go的解析器大概是跟随系统?)
再就是用_txt_.这种识别也是不可接受的 应该在其他地方设置 因为真实流量离开也要经过 DialSystem() 网站可以直接跨域访问 _txt_.example.com 检查连接是否被重定向探测有没有被xray代理

@j3l11234 j3l11234 changed the title Add query txt record for server endpoint redirection Add query srv record for server endpoint redirection Feb 20, 2025
@j3l11234
Copy link
Author

首先txt记录端口好像不是什么标准行为 用也是用srv 之前跟人讨论过这个问题 后来不了了之了 一个问题是内置DNS面向的是IP 并不支持其他类型解析 以及处理缓存问题(直接用go的解析器大概是跟随系统?) 再就是用_txt_.这种识别也是不可接受的 应该在其他地方设置 因为真实流量离开也要经过 DialSystem() 网站可以直接跨域访问 _txt_.example.com 检查连接是否被重定向探测有没有被xray代理

我现在改成了使用配置判断,以及使用了srv记录。

@Fangliding
Copy link
Member

这样好像有点复杂了 而且只支持了vless和vmess 把其他出站全改一遍好像也不太好

@j3l11234
Copy link
Author

j3l11234 commented Feb 20, 2025

这样好像有点复杂了 而且只支持了vless和vmess 把其他出站全改一遍好像也不太好

其实比较理想的应该是放到 StreamSettings ->sockopt ->domainStrategy 下,你觉得如何?

@Fangliding
Copy link
Member

sockopt是可以接受的 就像你的第一个实现但是从sockopt读出来而不是从目标地址
domainStrategy是控制要不要把域名解析为IP的 我觉得可以单独放一个选项 srvStrategy PortOnly TargetOnly PortAndTarget (有必要么? 还是说true or false就行了) 然后尝试解析并重置目标 放在domainstrategy前面 这样target被重置后还是可以被它正确解析为ip
当然还得看rprx怎么看

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

既然只是改 port 的话直接把 port 改为 address 那种可以填域名吧

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

        "address": "www.com",
        "port": "srv.com",

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

等下,SRV 是 IP 和 port 一起提供了吗

@j3l11234
Copy link
Author

既然只是改 port 的话直接把 port 改为 address 那种可以填域名吧

我觉得这个方式也不错,就是要改port的格式,也要改rpc一整套声明。 我还是倾向于 srvStrategy PortOnly TargetOnly PortAndTarget 这个方案,这个可以连address也一块改,更加灵活。 因为srv记录本来就是支持address和port的。

@j3l11234
Copy link
Author

j3l11234 commented Feb 20, 2025

等下,SRV 是 IP 和 port 一起提供了吗

是的,我的截图里面吧IP(域名也行)一块给打码了。

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

把 address 填成一个指针的确更加灵活,但感觉必要性不大?如果你能控制那个 address 解析出来什么,随时都能改 cname

这样的话我感觉设计得简单一些,弄个 "port": "txt.com" 似乎更好

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

就是 address 和 port 的解析直接各自分开,也不用搞那些 strategy 设置了

@j3l11234
Copy link
Author

把 address 填成一个指针的确更加灵活,但感觉必要性不大?如果你能控制那个 address 解析出来什么,随时都能改 cname

这样的话我感觉设计得简单一些,弄个 "port": "txt.com" 似乎更好

就是考虑通用性,如果我想根据srv来改address和端口,这样还是增加配置项更好?

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

那就这样愉快地决定了,txt 记录就填个 "12345" 吧,不用标明键是 port,你试下是否可行

这样还有一个好处是你可以用完全无关的域名去存这个 port,防止用同一个域名存的话特征太明显

srv 这种记录本身应该没什么人用,有点扎眼了

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

就是考虑通用性,如果我想根据srv来改address和端口,这样还是增加配置项更好?

你去弄个 srv,和给 port 加个域名解析,效果是完全一样的,没有哪个更通用的区别

给 port 加个解析就不用加其它配置项,而且可以完全和 address 分离,隐蔽性更好

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

如果是 srv 的方案,address 填了,port 置 0 就默认按 srv 更好,不需要加配置,不过 port 为 0 又有 tls 时可能默认 443 更好?

话说分享链接搞成这样 vless://[email protected]:port.com? 会不会有问题

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

我看了下 Go 的 url 解析器 Port() 是返回 string 的,你试下这东西丢进去能不能正常区分 hostname 和 port

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

要搞更简单一点的话甚至你能用 A 记录藏 port

@j3l11234
Copy link
Author

我看了下 Go 的 url 解析器 Port() 是返回 string 的,你试下这东西丢进去能不能正常区分 hostname 和 port

net.destination里面定义的port是数字的,得一层一层改成string

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

net.destination里面定义的port是数字的,得一层一层改成string

这个别动了吧,port 置 0,可以另加一个 PortDomain 是 string

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

而且我感觉 txt 记录都有点扎眼,还要改内置 dns,要不就 a 记录,前两位不管,后两位为 port,256 进制

@j3l11234
Copy link
Author

而且我感觉 txt 记录都有点扎眼,还要改内置 dns,要不就 a 记录,前两位不管,后两位为 port,256 进制

用这个方式,对lucky的webhook太不友好了。 用txt和srv记录,本身也没啥影响吧?不一定非得是xray的服务呀,别的服务一样可以用srv去获取服务端口。

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

我感觉似乎要么就装成正经 srv,要么就装成正经 a 记录,明文 DNS 查也挺正常,txt 有点不上不下

@j3l11234
Copy link
Author

j3l11234 commented Feb 20, 2025

我感觉似乎要么就装成正经 srv,要么就装成正经 a 记录,明文 DNS 查也挺正常,txt 有点不上不下

那还是正经srv吧,微软很多服务会用srv。 我理解要伪装的是传输的数据,而不是获取端口的步骤。 用srv记录拿grpc端口也是很常见的

@Fangliding
Copy link
Member

我觉得port 0这种最好别乱用 不知道其他部分是怎么处理port0的 可能在核心有的地方或者gui客户端的解析器里被视为非法值然后寄掉
srv记录跟请求的域名没关系 完全可以用一个独立的域名存放srv记录 这到都是次要的

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

要用 srv 的话是否应该 port 为 0 就默认取自 srv,不需要加选项,也方便分享

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

或者 "port": "srv" 这种

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

core 的逻辑可以改,gui 的逻辑也可以改,port 0 也能分享,port srv 这种虽然似乎也能分享但兼容性更差些

@j3l11234
Copy link
Author

可能在核心有的地方或者gui客户端的解析器里被视为非法值然后寄掉

说实话我感觉 port 0 的兼容性更好

内部反向代理用得就是port0吧? 如果port=0,就从address中去解析srv记录,然后反过来修改address和port,这个流程我是ok的。

@Fangliding
Copy link
Member

这始终是个小众功能 大都是要打洞回家的人用的 几乎都得自己手搓一份配置 照顾分享链接没啥意义

@j3l11234
Copy link
Author

这始终是个小众功能 大都是要打洞回家的人用的 几乎都得自己手搓一份配置 照顾分享链接没啥意义

对。。。基本上就是墙内对墙内。但是我还是希望对整体的改动最小。分享机制尽量不要被破坏

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

port 0 就是没有 port,实际上是无法连接的“未定义”,我觉得意义上是没问题的,只是如果有 tls 时默认 443 的逻辑的话得改

@Fangliding
Copy link
Member

举个例子 freedom的redirect的0端口意思是跟随请求端口的意思 跟这个就冲突的

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

我试了下 core 的 port 0 是连不上,NG 的 port 0 是不给保存,现在我们给 port 0 定义一个行为是没问题的

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

举个例子 freedom的redirect的0端口意思是跟随请求端口的意思 跟这个就冲突的

啊这,我再想一下

那要不 port srv

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

我提出 port a 记录这种,是觉得这个功能对反审查也是可以有意义的,就是把 port 藏在最普通的 a 记录里,明文 DNS 查也正常

以前他们不是有动态端口吗,都需要服务端有一个主端口来下发端口,现在可以通过 DNS 直接查到了,一开始就不一定什么端口

srv 记录的话还是相对小众,可以被针对

@Fangliding
Copy link
Member

Fangliding commented Feb 20, 2025

真的不用上升到这个层面了 这和隐蔽不隐蔽没关系 只是一个打洞player需要的功能 我拒掉过不止一个两个了 理由是完全可以通过订阅系统下发 我这次没反对是因为这么多人提了可能确实有人需要 以及放在这里再在sockopt配置是不错的选择 还有更灵活的用法比如使用freedom+srv重定向某些请求
真要动态端口也是QUIC那种 那种得修改dialer让它跳端口(参考hy端口跳跃) 和这个功能也不搭边

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

那就 "port": "srv" 这样配置吧,指定 address 是 srv,也方便分享到手机上,至于 port a 记录以后再说

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

或者 "fromSrv"

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

我感觉你们想加个 sockopt 带那么多选择有点复杂了,很多 GUI 也不会支持,"fromSrv" 这种未来也可以支持 port a 记录

@j3l11234
Copy link
Author

@Fangliding 思虑再三,还是按照你的建议,使用sockopt进行判断,考虑到多种情况,同时支持了srv和txt。

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

我觉得加个 destinationStrategy 与这么多选择,虽然看着很工整,但真的没有必要

因为 address 是不需要填个指针的,这是 cname 干的事情,只有 port 才需要指针,指定 "port": "fromSrv" 即可

而且单个 destinationStrategy 这种,几乎没有 GUI 会给你做选项的,不像 port 你在 NG 上也能填

@j3l11234
Copy link
Author

我有一个考虑的情况是,有可能会出现ddns失效的情况,这时候直接把ip:port写入到srv/txt记录中,这种情况下,srv和txt就起到了dns的作用,省略一次dns请求。

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

哪里省略一次 dns 请求了,而且 cname 才是只要一次吧

@j3l11234
Copy link
Author

如果我存入的srv的是 ip+port, 那我只要查询一次srv就可以拿到所有信息了,这时候dail就不需要额外发dns。
如果我存入的srv的时候域名+ip,或者域名用cname,那就得发两次请求。(第二次不管是a还是cname,都算一次请求)

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

"port": "fromSrv" 的意思就是连 address 都 override 了

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

就是我没懂你是哪里没理解到,在我看来只是配置方式的区别

@j3l11234
Copy link
Author

"port": "fromSrv" 是 address 和 port一起 override,
"port": "fromSrvPortOnly" 是port override,
这样子哈?

然后按照你下午所说,不改原来dest 那个interface里port的类型,新增一个PortDomain ?
这样又演变成我现在的方案了,新加一个属性去决定策略

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

只有 "fromSrv",没有 "fromSrvPortOnly"

代码里新加一个属性不等于新加了一个配置项,新加一个配置项对 GUI、对分享链接来说都是挑战

@Fangliding
Copy link
Member

Fangliding commented Feb 20, 2025

就是我没懂你是哪里没理解到,在我看来只是配置方式的区别

因为出站parse目标的格式是不一样的 就和我说的一样又要到每个出站的改 但是sockopt是统一的 而且本来就算干这个的 一直说核心改了GUI也会改 为什么不希望GUI支持sockopt呢(

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

我觉得要不还是 port a 记录,我之前有点想放弃它是因为怕某个环节不尊重 TTL,但又想了下貌似 SRV 也不会有特殊待遇

@RPRX
Copy link
Member

RPRX commented Feb 20, 2025

为什么不希望GUI支持sockopt呢(

要不把 sockopt 整个像 extra 那样塞进分享链接和 GUI

@Fangliding
Copy link
Member

整理了一下脏乱的大段if 无意义的for循环
有可返回的错误直接返回就行了 没必要重复再打日志 都去掉了
有个奇怪的条件判断不知意义为何 见181行

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.

3 participants