Skip to content

luci-app-ssr-plus: Add fake-ip mode and Fix Upload yaml config cannot use external DNS resolution. - #2044

Merged
zxlhhyccc merged 1 commit into
fw876:devfrom
zxlhhyccc:fake-ip
Sep 12, 2026
Merged

zxlhhyccc merged 1 commit into
fw876:devfrom
zxlhhyccc:fake-ip

Conversation

@zxlhhyccc

@zxlhhyccc zxlhhyccc commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

同时修复了mihono核心情况下ech配置生成问题。

@gongdao123

Copy link
Copy Markdown

@zxlhhyccc 刚更新了,目前测下来一切正常。我用到明早,看看稳定性。

@zxlhhyccc

zxlhhyccc commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator Author

@gongdao123 烦请务必测试一下:fake-ip模式切换时,规则文件备份和恢复是否包含198.18.0.1/16的规则,因为fake-ip模式才需要198.18.0.1/16的规则,不启用fake-ip模式不需要198.18.0.1/16规则。
具体测试是:
1、当fake-ip模式禁用时,持久化文件是否是fake-ip模式的规则,也就是运行非fake-ip模式时,持久化文件应该不能包含198.18.0.1/16的规则。
2、从非fake-ip模式切换到fake-ip模式时,持久化规则是否有198.18.0.1/16的规则,也就是运行fake-ip模式时,持久化文件应该包含198.18.0.1/16的规则。

@gongdao123

Copy link
Copy Markdown

@zxlhhyccc 按你的要求测了,两项都通过,重复两轮结果一致。

测试方法:把每轮拆成 stopstart 两个观察点,这样能同时覆盖你说的「备份」和「恢复」两个环节(PERSIST_FILEBACKUP_FILE 在 stop 期间会互换)。共做四轮:禁用 → 启用 → 禁用 → 启用。

1、禁用 fake-ip 时,持久化文件不含 198.18 规则

轮次 PERSIST 字节数 含 198.18.0.0/16 实时 nft
第1轮 禁用 146606 0 0
第3轮 禁用 146605 0 0

2、切换到 fake-ip 时,持久化文件含 198.18 规则

轮次 PERSIST 字节数 含 198.18.0.0/16 实时 nft
第2轮 启用 147064 5 5
第4轮 启用 147065 5 5

备份/恢复流转

以第2轮(禁用 → 启用)为例:

stop  后:  PERSIST 不存在              BACKUP 146606 字节, 含198.18=0   ← 备份的是旧(禁用)模式
start 后:  PERSIST 147064 字节, 含198.18=5   BACKUP 不存在              ← 未恢复陈旧备份,已按新模式重建

反方向(第3轮,启用 → 禁用)同样正确:

stop  后:  BACKUP 147064 字节, 含198.18=5    ← 备份的是旧(启用)模式
start 后:  PERSIST 146605 字节, 含198.18=0   ← 按新模式重建,198.18 规则已清除

陈旧备份被正确丢弃而非直接恢复,ENABLE_FAKE_IP_CHANGED 的判断生效。

/tmp/.last_enable_fake_ip 在 stop 后仍保持旧值、start 时才更新,这个差值正是触发重建的依据:

时刻 uci 设置 /tmp/.last_enable_fake_ip
第2轮 stop 后 1 0(旧值)
第2轮 start 后 1 1(已更新)

连通性

八次检查中七次正常:

  • fake-ip 启用时:google/generate_204 → 204,zh.wikipedia.org 解析为 198.18.0.x
  • fake-ip 禁用时:zh.wikipedia.org 解析为真实 IP 103.102.166.224(Wikimedia),redir-host 正常

第1轮有一次 google: 000,但第3轮同配置下为 204。这属于重启后首个请求的偶发失败(我另外用 16 个全新域名做过基线测试,稳定有 2-3 个首次访问失败,与 DNS 传输方式和本改动均无关),不是本次改动引入的问题。

环境

ImmortalWrt 25.12.1 r37978-cd0a06bfd3fd,mihomo v1.19.30,run_mode=routerpdnsd_enable=7clash_url 类型订阅(自带完整 dns 段)。

另:你描述里写的 198.18.0.1/16 是配置中 fake-ip-range 的形式,nft 规则里会规范化为 198.18.0.0/16,我按后者统计。

@zxlhhyccc

Copy link
Copy Markdown
Collaborator Author

@gongdao123 请问你是按照这个commit测试的吗?
image

@gongdao123

Copy link
Copy Markdown

是的 @zxlhhyccc
Screenshot 2026-09-10 at 23 33 47

@zxlhhyccc

Copy link
Copy Markdown
Collaborator Author

@gongdao123 OK!那是不是应该可以合并了?另外,准备添加mihomo内核清理dns缓存功能,你认为有必要吗?因为添加fake-ip后,我感觉可能存在dns缓存问题导致比如:油管网页有时要过几分钟才能打开,或者关闭浏览器重新开启浏览器也会正常。

@zxlhhyccc
zxlhhyccc force-pushed the fake-ip branch 4 times, most recently from c3af9d9 to 730af42 Compare September 10, 2026 16:36
@zxlhhyccc

zxlhhyccc commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator Author

@gongdao123 更新了依赖,没有这个依赖,mihomo的生成的配置中ech取值异常,因为mihomo的ech取值是TYPE65的base64编码,配置生成脚本使用了dig生成TYPE65的base64编码。如果直接是域名的话配置是错误的,会导致不能运行。
官方文档:
image

@gongdao123

Copy link
Copy Markdown

@zxlhhyccc 关于清理 DNS 缓存功能——建议不要加,方向是反的。

你描述的症状(油管过几分钟才能打开、重开浏览器就正常)是 fake-ip 映射丢失,不是缓存陈旧。profile 里只有 store-selected、没有 store-fake-ip,mihomo 每次重启都会丢掉整个 fake-ip 映射表,而 dnsmasq(cachesize=8000)和浏览器仍缓存着旧的 198.18.x.x。客户端拿旧地址来连,mihomo 反查不到域名就放弃:

[Metadata PreHandle] error: fake DNS record 198.18.0.129 missing
[Metadata PreHandle] failed to sniff a domain for connection ... 198.18.0.129:443, give up

等客户端缓存过期才恢复(几分钟),重开浏览器则是清掉了浏览器自己的 DNS 缓存。清 mihomo 的 DNS 缓存等于主动制造这个状态。

A/B 实测(curl --resolve 强制使用旧 fake-ip,模拟客户端缓存未过期):

取得 fake-ip 重启前 重启后新解析 用旧地址访问
现状 198.18.0.129 301 198.18.0.4 000
store-fake-ip: true 198.18.0.7 301 198.18.0.7 301

加上之后重启前后 fake-ip 不变,旧地址依然有效:

profile:
  store-selected: true
  store-fake-ip: true

cache.db 插件已经在持久化了(init 脚本里为 store-selected 做的那套),复用同一个文件,零额外成本。需要注意 fake-ip-range 变更时要让 cache.db 失效。

需要的话我提个 PR。

@gongdao123

Copy link
Copy Markdown

@zxlhhyccc ECH 这个修复认同。dig 缺失时 output:match("ech=([^%s]+)") 返回 nil,配置里就会填进域名而不是 base64 值,mihomo 直接起不来。

两点补充:

  1. 你上面写的是 TYPE5,文档和你代码里都是 TYPE65(HTTPS 记录),TYPE5 是 CNAME。应该只是笔误。

  2. 建议 fetch_ech_config()dig 不存在时显式报错或跳过,而不是静默返回 nil。现在「dig 没装」和「该域名确实没有 ech 记录」两种情况返回值相同,都要等配置生成错值、mihomo 起不来才暴露。加一个 command -v dig 检查会好排查很多。

@zxlhhyccc

zxlhhyccc commented Sep 11, 2026

Copy link
Copy Markdown
Collaborator Author

@gongdao123 你提的两个建议中:加上store-fake-ip: true是用于缓存持久化,可行也是对的。两个建议你提一个PR,我来合并,我现在都有点晕。

@zxlhhyccc

Copy link
Copy Markdown
Collaborator Author

cache.db 插件已经在持久化了(init 脚本里为 store-selected 做的那套),复用同一个文件,零额外成本。需要注意 fake-ip-range 变更时要让 cache.db 失效。

@gongdao123 cache.db 生成在生成的配置路径,在停止运行或重启时会自动删除,这个问题如果要持久化,必须在停止或重启且节点未变化时比照nft规则进行备份,切换节点,这个持久化文件仍然需要删除吧?

@gongdao123

Copy link
Copy Markdown

@zxlhhyccc PR 提好了:zxlhhyccc#1(ECH 那条你在 f4b0c56 已经做了,所以只剩 store-fake-ip)。

你问的 cache.db 三点,正文里有详细数据,简短版:

1. 不会自动删除。 运行目录里的是软链接,真实文件在 CLASH_CONFIG_DIR

/var/etc/ssrplus/clash-cfg024a8f/cache.db -> /etc/ssrplus/clash/cfg024a8f.cache.db

init:24   CLASH_CONFIG_DIR="/etc/ssrplus/clash"
init:272  get_clash_state_file() { echo "$CLASH_CONFIG_DIR/$1.cache.db"; }
init:698  mv -f "$workdir/cache.db" "$state_file"

重启实测:131072 字节 23:57 → 131072 字节 00:01,文件仍在。所以 store-selected 的持久化机制已经建好了,不需要再比照 nft 规则做备份。

2. 切换节点不需要删,删了有害。 fake-ip 池是「域名 ↔ 198.18.x.x」映射,与哪个节点承载流量无关;删掉会连带丢失 store-selected,并重新制造旧映射失效的问题。而且文件按 sid 命名(cfg014a8f.cache.db / cfg024a8f.cache.db),切换订阅本身就是隔离的。

3. fake-ip-range 变化也不用管,mihomo 自己会失效旧池。 实测把 range 改成 198.20.0.1/16、不删 cache.db 重启,直接返回 198.20.0.45,服务正常。我上一条说「range 变更时要让 cache.db 失效」是多余的,收回。

@zxlhhyccc

Copy link
Copy Markdown
Collaborator Author

@gongdao123 在你提交前我自己改好测试了,还是存在差不多问题,只是比没加store-fake-ip: true要好一些,暂时不管了,我再提交合并PR。

@zxlhhyccc

Copy link
Copy Markdown
Collaborator Author

@gongdao123 已重新提交并合并了PR,请测试。

@gongdao123

Copy link
Copy Markdown

@zxlhhyccc 看到 a05eb352 已经加好了,和我那个 PR 覆盖范围一致,所以 zxlhhyccc#1 我关掉了。

关于「还是存在差不多问题」——可能不是同一个原因。我这边独立测过:16 个全新域名(都在 gfwlist 内)首次访问,稳定有 2-3 个直接失败、重试即成功;这个比例在 DNS 上游用 UDP / TCP / DoH 三种传输方式下完全一样,与 fake-ip 映射无关。

所以 store-fake-ip 修掉的是「重启后旧地址失效」那一类(A/B 实测 000 → 301),剩下的首次访问不稳应该是另一条路径。

你先合并,这个我后面继续查,有结论再单独开 issue。

@zxlhhyccc

Copy link
Copy Markdown
Collaborator Author

@gongdao123 我是怀疑dns缓存问题,所以前面我提到要添加一个清理dns缓存。

@zxlhhyccc
zxlhhyccc force-pushed the fake-ip branch 2 times, most recently from 9e09efa to 08f5b0b Compare September 12, 2026 06:50
@gongdao123

Copy link
Copy Markdown

@zxlhhyccc 刚编译完,看到你又改了好多。新的改动是什么作用呢?

@zxlhhyccc

zxlhhyccc commented Sep 12, 2026

Copy link
Copy Markdown
Collaborator Author

@gongdao123 添加了tcp-concurrent: true和unified-delay: true,嗅探添加了force-dns-mapping: true和parse-pure-ip: true、force-domain,同时添加了嗅探cf的端口,非fake_ip模式允许嗅探。修复了上传yaml配置不能删除临时文件问题.....,目前用起来比昨日好用多了,应该是基本上正常了。
打算合并了。

@zxlhhyccc
zxlhhyccc force-pushed the fake-ip branch 2 times, most recently from 6f5265b to 70a7e0b Compare September 12, 2026 07:33
@zxlhhyccc

Copy link
Copy Markdown
Collaborator Author

@gongdao123 大佬,还有什么建议需要搞的吗?没有的话打算合并了。

@zxlhhyccc
zxlhhyccc merged commit b96067c into fw876:dev Sep 12, 2026
7 checks passed
@gongdao123

gongdao123 commented Sep 12, 2026

Copy link
Copy Markdown

@zxlhhyccc 合并后的版本已经刷真机测过,fake-ip 正常:服务能起、nft 198.18.0.0/16 5 条、53 与 5335 一致、16 个全新 gfwlist 域名冷启动 16/16 通。find-process-mode: off / tcp-concurrent / unified-delay / sniffer 端口扩充都正确生效。log-level 从 silent 提到 info 对排查帮助很大。

之前那个首访卡顿:大概率是机场节点,不是插件

我在上面说过会继续查,结论是跟插件无关。用 ms 时间戳把 /logs?level=debug 和 curl 分段对齐:

300.787  [TCP] ... --> lwn.net:443 match Match using 规则外路由选择[台湾05]
         ←──── 4.36 秒,零日志输出 ────→
305.15   TLS 握手完成

卡顿完整落在选完出站之后。几个旁证:

  • 同一域名连续请求 20 次,全部 0.25-0.45s,不是随机抖动,只有首次
  • 交给节点域名tls 4.5-6s;pure-IP 路径交真实 IP 时 0.3-2.0s
  • 把 DNS 换成 DoT(解析成功率 12/12、每次约 0.15s)之后,页面加载一点没变tls 中位数仍是 ~4.8s

区别只在"谁来解析这个域名",所以指向出口侧的解析器。我之前猜的两个方向(6001 条无 no-resolve 的 IP-CIDR 强制解析、DNS 传输方式)都是错的——命中 DomainSuffix 规则、完全不触发解析的域名一样卡。

顺便说一声 sniffer.override-destination: false 不能当解法:fake-ip 靠它把假 IP 换回域名,关掉之后我这边走代理的全挂,只剩直连。

一个建议:tunnel_forward:53 会退化成明文 UDP

format_dns_server()8.8.4.4:53 映射成裸 8.8.4.4,即 UDP:53,这个值同时进 dns.fallbacknameserver-policy["geosite:geolocation-!cn"]。配上 respect-rules: trueudp: false 的 SS 节点:

[DNS] resolve www.eff.org A from udp://8.8.4.4:53
代理 UDP is not supported
[UDP] mihomo --> 8.8.4.4:53 doesn't match any rule using DIRECT

墙外域名的解析就明文 UDP 直连出去了,投毒是实测到的:www.metafilter.com2a03:2880:f10a:83:face:b00c:0:25de

同 12 个冷域名的解析成功率PUT /configs 重载会清 resolver 缓存,每轮都是冷的):

tunnel_forward 成功 失败
8.8.4.4:53(默认,裸 UDP) 11 1
1.1.1.1:53(预置项之一) 0 12,均 5.001s context deadline exceeded
tls://8.8.4.4:853 12 0,约 0.15s

更正一处:这条评论最初写的是 8.8.4.4:53 6/12 失败,把效果量说大了。隔一段时间重跑是 11/12 成功——GFW 的投毒强度随时间漂移,我那次赶上了坏时段。裸 UDP 平时大多能用,但不稳定,且答案可能是投毒结果;1.1.1.1:53 在国内被打得最狠,基本不可用。另外这个差异只影响解析成功率,不影响页面速度(见上一节)。

你这次把 o.datatype 放开、is_valid_dns() 支持 scheme,所以填 tls://8.8.4.4:853 就能修,不用改代码,这点很好。只是下拉框预置的 11 个选项全是 :53(还包含 1.1.1.1:53 这种基本不通的),用户不手填就必然走上明文 UDP——建议默认值或预置项里加一个 :853 / :443 的。

环境:ImmortalWrt 25.12.1 r37978-cd0a06bfd3fd,mihomo v1.19.30,run_mode=routerpdnsd_enable=7clash_url 订阅。

@zxlhhyccc

Copy link
Copy Markdown
Collaborator Author

@gongdao123 我整理输的多个全部是https://的dns....

@gongdao123

Copy link
Copy Markdown

@zxlhhyccc 可能是 运营商的 关系。
我这边 最后设的是 tls://8.8.4.4:853

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.

2 participants