luci-app-ssr-plus: set a nameserver for mihomo's built-in DNS - #2040
luci-app-ssr-plus: set a nameserver for mihomo's built-in DNS#2040gongdao123 wants to merge 1 commit into
Conversation
When the DNS resolution mode is mihomo's built-in DNS (pdnsd_enable=7), the generated dns section enables DNS but never sets any nameserver. mihomo applies its defaults before patching them with the YAML, so the absent key leaves the built-in nameserver list in place: doh.pub and AliDNS over TLS. Both are encrypted, but both are domestic resolvers and cannot resolve blocked domains correctly, so those domains end up pointing at forged addresses and surface as intermittent TLS handshake failures. Nothing is logged, because the "NameServer cannot be empty" check never fires against a non-empty default. Two config paths never set a nameserver at all: the aggregate node built from a subscription (buildMihomoSubscribeYaml in subscribe.lua) and the single-node runtime documents built here. A Clash subscription that ships its own dns section is unaffected. Every other DNS mode already honours the existing "Anti-pollution DNS Server" option (tunnel_forward): dns2tcp, dns2socks, chinadns-ng and mosdns all read it. Only the mihomo path ignored it. What makes those modes work is not encryption but that the query is resolved outside the censored network, which is what dns2tcp/dns2socks provide. Reuse tunnel_forward as dns.nameserver and set respect-rules so the query follows the routing rules into the tunnel. respect-rules requires proxy-server-nameserver, so bootstrap it from the WAN-provided resolver and fall back to a public resolver when none is available; mihomo parses that list with respect-rules disabled, so the bootstrap cannot deadlock. The merge path only fills what is missing, so a subscription that already carries dns.nameserver keeps its own configuration untouched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
@gongdao123 经测试,代理失败。 死锁过程:
请按照mihomo的配置规则再核实一下。 |
|
@gongdao123 我已经根据你的pr进行了修正,但是有一个问题,如果是二级路由,get_wan_nameserver函数获取的IP是上级路由的内网IP(即:网关,比如:192.168.2.1),该IP不能进行dns解析,会导致无法代理,只有一个办法,加入直连规则即可解决。 |
|
理解了,我这边发现dns解析有问题是直接改的 clash 配置文件,所以想到反馈一下。 |
|
@gongdao123 你的clash配置文件怎么改的? |
|
我只加了这一段。 |
|
@gongdao123 不是你说的问题,我已经在修了,准备mihomo核心添加enhanced-mode: fake-ip(目前你的原始配置),待完善后你测试一下 |
|
好的 没问题 @zxlhhyccc |
|
@gongdao123 因添加mihomo的fake_ip功能,最终提交的修改如无意外在本周末会提交,到时请您测试,另外,你发我的yaml节点是失效了吗?昨天都可以用来测试正常代理,今天咋不行?能否发一下最新的yaml文件? |
|
可以的,我怎么单发给你 @zxlhhyccc |
@gongdao123 上次我发你了: zxlhhy@gmail.com |
|
已经发了,您看看。 @zxlhhyccc |
|
@gongdao123 好的,明天再验证一下,没有问题我就提PR了。 |
|
@gongdao123 终于差不多搞定了,改动了很多地方,同时修了昨天存在的bug,明天提PR你能否测试一下,如没有问题我就合并。 |
|
@gongdao123 已提交PR,请测试,结果请告知,谢谢!没问题我合并,目前我测试正常。见PR: #2043 |
|
好的 我今天测试一下。 |
@gongdao123 测试了吗? |
如何了 |
|
试过了,昨天反复试了几次。只要开了 fake ip, ssrplus 的服务就开不起来,关了就能开起来。 @zxlhhyccc 我订阅链接单发你,很容易复现。开 fake ip,服务就开不起来。日志看起来很正常。
|
修复 #2039。
问题
DNS 解析方式为 mihomo 内置 DNS(
pdnsd_enable=7)时,插件生成的dns段没有nameserver。mihomo 的配置解析是「先套内置默认值,再用 YAML 覆盖」(config/config.go:604→:612),所以缺失的键保留内置默认 —— v1.19.28 下是https://doh.pub/dns-query和tls://223.5.5.5:853。两者虽然加密,但都是国内递归解析器,无法正确解析被封锁的域名,结果指向伪造 IP,表现为间歇性 TLS 握手失败。parseDNS里的len(cfg.NameServer) == 0校验对非空默认值不触发,所以问题完全静默,日志无任何提示。两条路径无条件受影响(都不写
dns.nameserver):subscribe.lua:869buildMihomoSubscribeYaml()—— 订阅聚合生成的「Mihomo 总节点」clash_yaml.lua的build_tuic_runtime_doc/build_single_proxy_runtime_doc/build_shadowsocks_runtime_doc—— 单节点运行时配置自带
dns:段的机场 Clash 订阅不受影响。改动
项目已有「反污染 DNS 服务器」配置项
tunnel_forward,其他每种 DNS 模式都读取它(dns2tcpinit.d/shadowsocksr:166、chinadns-ng:1329、mosdns:1272、dns2socks),只有 mihomo 路径忽略。本 PR 让 mihomo 路径复用它:build_dns_upstreams()—— 读tunnel_forward,产出nameserver/respect-rules/proxy-server-nameserverbuild_dns_section()—— 收拢原先三处逐字重复的dns表,修掉单节点生成器路径fill_missing_dns_upstreams()—— 在merge()中deep_merge之后调用respect-rules让 DNS 查询跟随rules进入隧道,与 dns2tcp/dns2socks 为其他模式提供的语义一致(起作用的关键属性是在墙外完成解析,而非加密本身),并且不需要知道用户订阅中的策略组名称。填充只在缺失时进行。 如果无条件写进 overlay,会因为 overlay 在
deep_merge中优先而覆盖掉机场自带的dns.nameserver,构成回归;放在 merge 之后按需填充可以避免,与已有的fill_empty_proxy_groups属同类处理。对照 mihomo v1.19.28 源码确认
respect-rules开启且未显式指定策略组时,查询跟随rules(proxyName = dns.RespectRules)config.go:1277-1278respect-rules要求proxy-server-nameserver非空,否则拒绝启动config.go:1407-1408proxy-server-nameserver以respectRules=false解析,走直连,不会死锁config.go:1437udp://host:port受支持,缺省端口 53config.go:1219第二条意味着两者必须成对写入,本 PR 始终如此。
测试
luac -p语法检查通过uci/has_nonempty_sequence/get_filter_aaaa后跑了 22 项断言,全部通过。覆盖:dns段缺失 /enable=false/ 缺nameserver/nameserver为空表nameserver时保持原样不覆盖(回归防护)respect-rules: false不被改写tunnel_forward为空时回落默认、自定义值正确生效build_dns_section()在dns_mode为7/ 非7时的enable取值尚未在真机上跑过打包后的完整流程,如果需要我补真机验证结果请告知。
另外 issue 里问过、这里再提一下:
enhanced-mode硬编码为redir-host且strip_runtime_conflicts会移除fake-ip-range/fake-ip-filter,我按「刻意设计」处理,本 PR 不涉及 fake-ip。🤖 Generated with Claude Code