You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
nft insert rule inet fw4 nat_output position 0 \
meta nfproto {ipv4} meta l4proto {tcp,udp} th dport 53 \
ip daddr {127.0.0.1} meta skgid != 65534 counter redirect to "$dns_port"
IPv6(第 1722/1743 行)— 劫持目标为 ::/0(所有地址):
nft insert rule inet fw4 nat_output position 0 \
meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 \
ip6 daddr {::/0} meta skgid != 65534 counter redirect to "$dns_port"
Activity
[-][代码疑问] nat_output IPv6 DNS 劫持目标:::/0 是否应为 ::1?[/-][+][讨论] nat_output IPv6 DNS 劫持目标 ::/0 与 IPv4 的 127.0.0.1 不对称,想请教是否有特殊考量[/+]huazhaochen01 commentedon Jul 29, 2026
主要跟 openwrt 下 ipv6 的 dns 分发机制有关
在 ipv4 场景下比较简单,openwrt 本地的 dnsmasq 默认监听在 127.0.0.1,系统本身的 resolv.conf 指向的基本上也是 127.0.0.1,所以 nat_output 里只限制 ip daddr {127.0.0.1} 就刚好能兜住路由器自身发出的所有 ipv4 dns 请求。
但是到了 ipv6 场景,openwrt 的 wan6 接口通过 dhcpv6 odhcp6c 从运营商获取 ipv6 之后,系统自动生成的 resolv.conf 会把运营商下发的公网 ipv6 dns 地址比如 240e:x:x:x 或 2408:x:x:x 直接写进去。这时候路由器自身发起的 ipv6 dns 查询,目标地址并不是 ::1,而是直接发往外网的公网 ipv6 dns 地址。
如果 ipv6 nat_output 也像 ipv4 一样只限制 ::1,那路由器自身发出的这些 ipv6 dns 请求就会直接绕过 openclash 跑去查公网 ipv6 dns,引发严重的 ipv6 dns 泄露,也就是常见的运营商 ipv6 dns 抢答问题。
所以 ipv6 nat_output 必须用 ::/0 把所有目标为 53 端口的 ipv6 出站流量全量兜住重定向给 clash dns,同时配合 skgid != 65534 规则排除掉 clash 核心自身发起的请求,防止产生回环。
morytyann commentedon Jul 29, 2026
嗯?
ocoj commentedon Jul 29, 2026
感谢 @huazhaochen01 的详细解答,非常清晰。之前误以为
::/0是 IPv4127.0.0.1的对称 bug,没考虑到 OpenWrt 的 resolv.conf 会被运营商写入公网 IPv6 DNS 这一层。现在已经理解::/0+skgid != 65534的设计用意——防止路由器自身 IPv6 DNS 泄漏,同时排除 clash 自身流量防回环。已将之前的自定义防火墙脚本和定时巡检清理掉,恢复了默认设置。谢谢!
GeekXtop commentedon Jul 31, 2026
@huazhaochen01 @ocoj 这问题我也遇到了,已经提了修复 #5252,已合并到 dev。
使用 AI 分析了一下原始提交,以下含 AI 生成内容。
::/0 不像刻意设计,更像手误。引入它的 d4cd7436 标题是 fix: dns hijack lo only for router self,意图明确是只劫持回环地址,IPv4 也确实写的 127.0.0.1,唯独 IPv6 写成了匹配全部地址的 ::/0,跟标题自相矛盾。而且那行连关键字都是从 v4 复制的——写的是 ip daddr 而不是 ip6 daddr,nft 根本解析不了,报错还被行尾的 2>/dev/null 吞掉,所以当时压根没装上。
后来 #3175 把语法修成了 ip6 daddr,但 ::/0 被一起带了下来。而那时 v4/v6 还共用同一个"是否已存在 hijack 规则"的判断,不区分协议族——v4 分支先跑并下发规则后,v6 分支的判断就被顶掉、整段跳过。直到 #5209 分离了 v4/v6 guard,这条规则才第一次真正出现在 nftables 里(版本:v0.47.117)。
我这边的具体故障:用 SmartDNS 做自定义 DNS,上游加了纯 IPv6 地址的服务器。规则生效后,SmartDNS 并发查询 v4/v6 上游时,v6 那一路就被 ::/0 劫持了——它会拦下本机除 OpenClash 核心(gid 65534)外所有发往任意 IPv6 地址的 53 请求,重定向到本地 clash,fake-ip 模式下秒回 198.18 段,比真正出网的 v4 请求快得多,于是被 SmartDNS 采纳。结果就是订阅地址和节点域名全解析成 fake-ip,订阅更新不了、节点也连不上。
vernesong commentedon Aug 1, 2026
@GeekXtop 改了
github-actions commentedon Sep 30, 2026
This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 5 days