Mahdi-zarei / nekoray

Qt based cross-platform GUI proxy configuration manager (backend: sing-box)
GNU General Public License v3.0
250 stars 17 forks source link

BUG: 内置DNS工作流程不符合预期 #50

Open soraneoumi opened 1 week ago

soraneoumi commented 1 week ago

描述问题

本地:IPv4 服务器:4&6 双栈

当内置DNS为如下设置时: 远程DNS 1.1.1.1 prefer_ipv6 直连DNS localhost ipv4_only Default DNS server: remote

且路由规则设置直连cn_IP时:

{
    "outbound": "direct",
    "rule_set": [
        "cn_IP",
        "cn_SITE",
        "geolocation-cn_SITE"
    ]
}

中国域名会解析出IPv6地址,浏览器获取到nekoray返回的IP后会导致无法访问: ERROR[0044] [1908416419 308ms] inbound/tun[tun-in]: dial tcp [240e:940:e009:182::1:1e]:80: connectex: A socket operation was attempted to an unreachable network. 自定义DNS object后此问题缓解:

{
    "final": "dns_proxy",
    "rules": [
        {
            "rule_set": "cn_SITE",
            "server": "dns_direct"
        }
    ],
    "servers": [
        {
            "address": "1.1.1.1",
            "detour": "proxy",
            "strategy": "prefer_ipv6",
            "tag": "dns_proxy"
        },
        {
            "address": "dhcp://auto", //设置为local或localhost时无法解析中国域名:DNS request timed out.
            "detour": "direct",
            "strategy": "ipv4_only",
            "tag": "dns_direct"
        }
    ]
}

预期行为: 中国域名只返回IPv4地址

实际行为: 返回双栈DNS地址,不设置rule-set时(参见上方rule-set)通过服务器访问IPv6地址,当设置rule-set时,通过direct访问并提示错误。

如何复现

请参见上方描述。

日志

log ``` DEBUG[0006] dns: exchange zz.189.cn. IN AAAA DEBUG[0006] dns: exchange zz.189.cn. IN A INFO[0006] [1576069611 1ms] router: found process path: \PATH\msedge.exe INFO[0006] [1576069611 1ms] outbound/wireguard[proxy]: outbound connection to [2606:4700:20::681a:d0a]:443 DEBUG[0006] dns: exchanged www.189.cn NOERROR 118 INFO[0006] dns: exchanged www.189.cn CNAME www.189.cn. 118 IN CNAME www.189.mixcdn.58cloud.com. INFO[0006] dns: exchanged www.189.cn CNAME www.189.mixcdn.58cloud.com. 118 IN CNAME www.189.cn.bsclink.cn. INFO[0006] dns: exchanged www.189.cn CNAME www.189.cn.bsclink.cn. 118 IN CNAME bj58cloud.v.bsclink.cn. INFO[0006] dns: exchanged www.189.cn A bj58cloud.v.bsclink.cn. 118 IN A 183.131.179.78 INFO[0006] dns: exchanged www.189.cn A bj58cloud.v.bsclink.cn. 118 IN A 183.131.179.75 INFO[0006] dns: exchanged www.189.cn A bj58cloud.v.bsclink.cn. 118 IN A 183.131.179.72 INFO[0006] dns: exchanged www.189.cn A bj58cloud.v.bsclink.cn. 118 IN A 183.131.179.70 INFO[0006] dns: exchanged www.189.cn A bj58cloud.v.bsclink.cn. 118 IN A 183.131.179.71 INFO[0006] dns: exchanged www.189.cn A bj58cloud.v.bsclink.cn. 118 IN A 183.131.179.74 INFO[0006] dns: exchanged www.189.cn A bj58cloud.v.bsclink.cn. 118 IN A 183.131.179.81 INFO[0006] dns: exchanged www.189.cn A bj58cloud.v.bsclink.cn. 118 IN A 183.131.179.73 INFO[0006] dns: exchanged www.189.cn A bj58cloud.v.bsclink.cn. 118 IN A 183.131.179.79 INFO[0006] dns: exchanged www.189.cn A bj58cloud.v.bsclink.cn. 118 IN A 183.131.179.80 INFO[0006] dns: exchanged www.189.cn A bj58cloud.v.bsclink.cn. 118 IN A 183.131.179.76 DEBUG[0006] dns: exchanged www.189.cn NOERROR 118 INFO[0006] dns: exchanged www.189.cn CNAME www.189.cn. 118 IN CNAME www.189.mixcdn.58cloud.com. INFO[0006] dns: exchanged www.189.cn CNAME www.189.mixcdn.58cloud.com. 118 IN CNAME www.189.cn.bsclink.cn. INFO[0006] dns: exchanged www.189.cn CNAME www.189.cn.bsclink.cn. 118 IN CNAME bj58cloud.v.bsclink.cn. INFO[0006] dns: exchanged www.189.cn AAAA bj58cloud.v.bsclink.cn. 118 IN AAAA 240e:f7:8e00:405::6:109 INFO[0006] dns: exchanged www.189.cn AAAA bj58cloud.v.bsclink.cn. 118 IN AAAA 240e:f7:8e00:405::6:106 INFO[0006] dns: exchanged www.189.cn AAAA bj58cloud.v.bsclink.cn. 118 IN AAAA 240e:940:e009:182::1:20 INFO[0006] dns: exchanged www.189.cn AAAA bj58cloud.v.bsclink.cn. 118 IN AAAA 240e:940:e009:182::1:1e INFO[0006] dns: exchanged www.189.cn AAAA bj58cloud.v.bsclink.cn. 118 IN AAAA 240e:940:e009:182::1:1d INFO[0006] dns: exchanged www.189.cn AAAA bj58cloud.v.bsclink.cn. 118 IN AAAA 240e:f7:8e00:405::6:10a INFO[0006] dns: exchanged www.189.cn AAAA bj58cloud.v.bsclink.cn. 118 IN AAAA 240e:940:e009:182::1:1b INFO[0006] dns: exchanged www.189.cn AAAA bj58cloud.v.bsclink.cn. 118 IN AAAA 240e:f7:8e00:405::6:10e INFO[0006] [138109783 0ms] inbound/tun[tun-in]: inbound connection from [fdfe:dcba:9876::1]:10608 INFO[0006] [138109783 0ms] inbound/tun[tun-in]: inbound connection to [240e:f7:8e00:405::6:109]:443 INFO[0006] [2965883874 0ms] inbound/tun[tun-in]: inbound connection from [fdfe:dcba:9876::1]:10609 INFO[0006] [2965883874 0ms] inbound/tun[tun-in]: inbound connection to [240e:f7:8e00:405::6:109]:443 DEBUG[0006] [138109783 0ms] router: sniffed protocol: tls, domain: www.189.cn DEBUG[0006] [2965883874 0ms] router: sniffed protocol: tls, domain: www.189.cn INFO[0006] [138109783 1ms] router: found process path: \PATH\msedge.exe INFO[0006] [2965883874 1ms] router: found process path: \PATH\msedge.exe DEBUG[0006] [138109783 1ms] router: match[6] rule_set=[cn_IP cn_SITE geolocation-cn_SITE] => direct DEBUG[0006] [2965883874 1ms] router: match[6] rule_set=[cn_IP cn_SITE geolocation-cn_SITE] => direct INFO[0006] [138109783 1ms] outbound/direct[direct]: outbound connection to [240e:f7:8e00:405::6:109]:443 INFO[0006] [2965883874 1ms] outbound/direct[direct]: outbound connection to [240e:f7:8e00:405::6:109]:443 ERROR[0006] [2965883874 1ms] inbound/tun[tun-in]: dial tcp [240e:f7:8e00:405::6:109]:443: connectex: A socket operation was attempted to an unreachable network. ERROR[0006] [138109783 1ms] inbound/tun[tun-in]: dial tcp [240e:f7:8e00:405::6:109]:443: connectex: A socket operation was attempted to an unreachable network. ```
Mahdi-zarei commented 1 week ago

理解您的困惑。当前配置符合预期,因为您将远程服务器用作“dns”服务器,会收到所需的“ipv6”地址,但该地址似乎由于您的本地机器不支持“ipv6”而无法使用。

解决此问题有两种方法:

与您设置的类似,在“dns”部分设置规则。
在“outbounds”部分设置“domain strategy”(此功能目前不可用,我将尝试稍后添加)。

因此,在您的特殊情况下,我相信手动设置“dns”规则是唯一可行的方法,应用程序中并无错误,因为处理此类需要手动干预的冲突并非本项目的目标。

Restia-Ashbell commented 1 week ago

你有设置域名策略吗,没有域名策略时,dns解析策略仅作为dns服务,路由仅匹配域名规则,不在cn规则集的cn域名不管经代理dns解析的是什么都会走代理才对

soraneoumi commented 1 week ago

你有设置域名策略吗,没有域名策略时,dns解析策略仅作为dns服务,路由仅匹配域名规则,不在cn规则集的cn域名不管经代理dns解析的是什么都会走代理才对

我的域名策略(inboud.domain_strategy)为空。 如我之前所提到的,在route.rule-set中将cn IP设置为direct之后会导致上述错误发生。因为直连DNS并没有读取route内容,使得geosite:cn通过直连DNS解析。 在arm64v8a设计的原版nekoray中,是没有这种现象的。

Restia-Ashbell commented 1 week ago

域名解析策略,没有域名策略,dns解析策略代理dns服务,域名代理,域名解析策略代理cn域名不管经代理dns解析的都是代理

我的域名策略(inboud.domain_strategy)为空。 如我之前提到的,在route.rule-set中将cn IP设置为direct之后会导致上述的错误。因为直连DNS并没有读取route内容,使得geosite:cn通过直连DNS解析。 在arm64v8a设计原版nekoray中,是没有这种现象。

没明白你的意思,我理解的你的问题是:有不在cn规则集的cn域名,由于远程dns使用prefer_ipv6得到一个cn的ipv6地址,然而只有在设置了inboud.domain_strategy时,才会在路由前转换成ip匹配到cnip走direct,然后没有ipv6的本地使用这个ipv6地址连接导致错误,否则不会匹配ip规则,这个域名会在路由中由于匹配不到cn域名规则走默认出站proxy

然而看你的日志,这明显是一个cn域名如果匹配ipv4_only的直连dns为什么会有AAAA是个问题,你提供的日志中也没有具体dns路由的过程

soraneoumi commented 1 week ago

没明白你的意思,我理解的你的问题是:有不在cn规则集的cn域名,由于远程dns使用prefer_ipv6得到一个cn的ipv6地址,然而只有在设置了inboud.domain_strategy时,才会在路由前转换成ip匹配到cnip走direct,然后没有ipv6的本地使用这个ipv6地址连接导致错误,否则不会匹配ip规则,这个域名会在路由中由于匹配不到cn域名规则走默认出站proxy

感谢你的跟进。首先请让我们明确一个前提条件:tun和tproxy入站只会是ip 不会有域名 我目前的配置为:开启 sniff + 关闭 domain_strategy(对应nekoray中的域名策略留空) + 关闭 sniff_override_destination(对应 nekoray 中的“探测结果用于路由判断” 此配置下 sing-box 的入站行为如下:

请注意:tun和tproxy入站只会是ip 不会有域名

  1. 当tun设备截取到DNS请求之后,Mahdi的nekoray会通过代理服务器向远程DNS查询结果。
  2. 因为我配置了prefer_ipv6,所以会返回v4&v6两种结果。
  3. 因为浏览器收到了nekoray返回的ipv6地址,则尝试使用ipv6地址通信,此时进入上述路由匹配。
  4. tun截取到这个链接之后,嗅探出域名为 www.189.cn (日志中的 router: sniffed protocol: tls, domain: www.189.cn),然后ip和域名一起进行匹配,匹配到直连 rule-set (日志中的 [rule_set](router: match[6] rule_set=[cn_IP cn_SITE geolocation-cn_SITE] => direct)
  5. 因为我的本地PC没有ipv6地址,导致通信失败。

上述过程中,直连DNS并没有参与。

Mahdi也在上面指出了,解决此问题可以 在“dns”部分设置规则在“outbounds”部分设置“domain strategy” 但我本人是不推荐使用后者的,因为在目前CDN普及的环境下,通过远程DNS解析出来的地址往往是对server所在地进行优化的。在这种场景下,会导致用户PC通过本地直连中国国外的CDN节点。 而在arm64v8a设计的原版nekoray中(我没有读过源码,此部分为猜测),在内核运行前,读取了简易路由的直连配置,并通过直连DNS解析其中的geosite。而避免了此特殊情况,实际测试中,同样的配置也无法在arm64v8a的原版nekoray中复现此问题。

Restia-Ashbell commented 1 week ago

没明白你的意思,我理解你的问题是:有不在cn规则集的cn域名,由于远程dns使用prefer_ipv6得到一个cn的ipv6地址,然而私有设置了时inboud.domain_strategy,才会在路由前打出ip匹配到cnip走direct,然后没有ipv6的本地使用这个ipv6地址连接导致错误,否则不会匹配ip规则,这个域名会在路由中由于匹配不到cn域名规则走默认出站代理

谢谢您的跟进。首先请让我们明确一个前提条件:tun和tproxy入站只会是ip 不会有域名 我目前所介绍的配置为:开启 sniff + 关闭 domain_strategy(对应nekoray中的域名策略留空) + 关闭 sniff_override_destination(对应nekoray 中的“探测结果用于路由判断” 此配置下的入站行为如下:

  • 如果入站是ip,那么出站还是ip,而且sniff出来的域名会和入站的ip一起进入路由规则匹配,可以同时匹配域名和ip规则
  • 如果入站是域名,那么出站还是域名,此时不会进行dns域名解析,域名直接进入域名匹配,不会匹配到ip地址等规则,

请注意:tun 和 tproxy 入站只会有 ip 不会有域名

  1. 当tun设备截取到DNS请求之后,Mahdi的nekoray会通过代理服务器向远程DNS结果。
  2. 因为我配置了prefer_ipv6,所以会返回v4&v6两种结果。
  3. 因为浏览器正在准备nekoray返回的ipv6地址,则尝试使用ipv6地址通信,此时进入上述路由匹配。
  4. tun截取到这个链接之后,嗅探出域名为www.189.cn(日志中的router: sniffed protocol: tls, domain: www.189.cn),然后ip和域名一起进行匹配,匹配到直连规则集(日志中的[rule_set](router: match[6] rule_set=[cn_IP cn_SITE geolocation-cn_SITE] => direct)
  5. 因为本地PC没有ipv6地址,导致通信失败。

上述过程,直连DNS并没有参与。

Mahdi也在上面指出了,可以在“dns”部分设置规则“outbounds”部分设置“domain policy”来 解决此问题,但我本人是不推荐使用这个的,因为在目前CDN普及的环境下,通过DNS解析出来的地址是对服务器所在地进行优化。在这种场景下,会导致用户PC通过本地直连中国国外的CDN节点。 而在arm64v8a设置原版nekoray中(我没有读过源码,此部分为猜测),在内核运行前,读取了本地路由的直连配置,并通过直连DNS解析其中的geosite。而避免了此特殊情况,实际测试中,同样的配置无法在arm64v8a的原版nekoray中复现此问题。

感谢你的详情说明,关于tun和tproxy入站只会是ip这点我是知道的,我的意思是入站的ip是前一步dns得到的,内核通过劫持了dns获得映射或者直接sniff得到其域名用于域名路由

我提出的日志中的问题是如果有开内置DNS的启用DNS路由的话,它的效果应该会和你自定义DNS object中

{
            "rule_set": "cn_SITE",
            "server": "dns_direct"
}

效果一致,对cn域名的dns请求使用ipv4_only的本地dns,然而出现了AAAA记录,这是异常的

另外,如果要让通过代理dns查询有cdn的域名返回的ip是本地cdn地址而不是远端cdn地址,可以参考文档中DNS rules (Enhanced, but slower) (1.9.0+) Without DNS leaks, but slower (1.9.0-alpha.2+)

soraneoumi commented 1 week ago

我提出的日志中的问题是如果有开内置DNS的启用DNS路由的话

在Mahdi的nekoray中,启用DNS路由已经被Default DNS server替代了

内核通过劫持了dns获得映射或者直接sniff得到其域名用于域名路由,而这个入站ip不会作为匹配ip规则的ip,除非拿不到域名就会作为纯ip去匹配ip规则

DEBUG[0003] [3189388549 3ms] router: sniffed protocol: tls, domain: www.189.cn
INFO[0003] [3189388549 4ms] router: found process path: \PATH\msedge.exe
DEBUG[0003] [3189388549 4ms] router: match[6] rule_set=cn_IP => direct
INFO[0003] [3189388549 4ms] outbound/direct[direct]: outbound connection to [240e:940:e009:182::1:1b]:443
ERROR[0003] [3189388549 5ms] inbound/tun[tun-in]: dial tcp [240e:940:e009:182::1:1b]:443: connectex: A socket operation was attempted to an unreachable network.
Restia-Ashbell commented 2 days ago

抱歉我之前没理解清楚,看日志原因是cn域名的解析走了远程dns取得ipv6地址,但在路由阶段又因为匹配cn域名或ip走了直连,本地没有ipv6于是无法连接,因此问题在于内置的DNS路由不生效,从你自定义DNS object后此问题缓解也可以得到证实,旧路由系统时,内置DNS路由就是用简易路由的域名规则,现在新路由的内置DNS路由不会自动使用路由里的规则直接走默认dns

我想另一个issues #62 也是这个原因,b站的域名解析走了默认的远程dns返回了b站的国外服务器地址,路由匹配域名又走了直连,但b站有区域限制,国内不能连接国外服务器于是打不开

soraneoumi commented 2 days ago

抱歉我之前没理解清楚,看日志原因是cn域名的解析走了远程dns取得ipv6地址,但在路由阶段又因为匹配cn域名或ip走了直连,本地没有ipv6于是无法连接,因此问题在于内置的DNS路由不生效,从你自定义DNS object后此问题缓解也可以得到证实,旧路由系统时,内置DNS路由就是用简易路由的域名规则,现在新路由的内置DNS路由不会自动使用路由里的规则直接走默认dns

我想另一个issues #62 也是这个原因,b站的域名解析走了默认的远程dns返回了b站的国外服务器地址,路由匹配域名又走了直连,但b站有区域限制,国内不能连接国外服务器于是打不开

是的,在原版的文档中也提到了这一点:直连 DNS 用以解析 服务器地址 和 绕过 域名。,也就是说,当用户在简易路由的bypass中填写了geosite:cn后,原版nekoray会用直连DNS解析这些域名。但是在Mahdi氏的版本中,此功能不生效,似乎已经被移除。仅提供上游DNS选择功能。