站点图标 ITGeeker技术奇客

IPv6 一开,旁路由就白配了:华硕 RT-BE88U + ImmortalWRT 的两种解法和一个隐藏的坑

家里这套网络我折腾了很久:华硕 RT-BE88U 当主路由拨号,一台刷了 ImmortalWRT 的Intel N100小主机当旁路由跑 OpenClash,全屋终端网关指向旁路由,分流、去广告、海外流量各走各的,一直很稳。

直到技术奇客ITGeeker.net打算上 IPv6开始就出现各种无法访问的问题了。

那天之后,YouTube 开始转圈,部分设备的分流直接失效,旁路由的流量统计里几乎看不到这些设备。查了一圈才明白:IPv6 把旁路由整个绕过去了。

这不是配置错了,是 IPv6 的设计如此。这篇文章把原理、两种落地方案,以及后面踩到的那个更隐蔽的坑(硬件加速让防火墙规则失效)一次讲清楚。

为什么”旁路由 + IPv6″天然打架

IPv4 时代的旁路由很好理解:主路由关掉 DHCP,终端拿到的网关和 DNS 都是旁路由的地址,流量自然先经过旁路由,再决定直连还是走代理。为了不出乱子,大家通常还会在主路由上把 NAT 关掉或者干脆不用 NAT——反正旁路由自己会处理。

IPv6 不是这么玩的。IPv6 默认不做 NAT,主路由通过 RA(路由通告)和 DHCPv6 给内网每个终端发一个独立的公网地址,同时告诉终端”默认网关是我”。终端拿到地址后,访问 IPv6 目标时直接走主路由,旁路由连包都看不到。

结果就是:

而且华硕官方固件(包括梅林)在 IPv6 的 RA 里不给你改网关的选项,想把 IPv6 默认网关强行指到旁路由,界面里根本找不到地方。这就是所有方案的分岔点。

两条路:过滤 AAAA,或者 NAT6 强接管

方案核心思路适合谁代价
A. 过滤 AAAA主路由正常发 IPv6,但旁路由的 DNS 把所有 AAAA 记录过滤掉,终端只能用 IPv4 出网大多数家庭;只要分流生效,不要求终端有公网 IPv6终端没有 IPv6 出口;依赖 DNS 全部走旁路由
B. NAT6 强接管旁路由自己发 RA、自己做 IPv6 NAT,终端把旁路由当 IPv6 网关必须让终端真正用公网 IPv6 跑代理配置复杂,容易和主路由的 RA 打架、断流

我的建议很明确:先上 A,除非你有明确的”终端必须用 IPv6″的需求。 A 方案稳定到几乎不会出问题,B 方案则是能用,但对固件和动手能力要求都高。

方案 A:过滤 AAAA,让终端老老实实走 IPv4

原理一句话:让 DNS 层面”看不见” IPv6 地址,终端自然就不会去连 IPv6。

主路由(华硕 RT-BE88U)

  1. 进 高级设置 → IPv6
  2. 联机类型选 Native
  3. 接口按实际情况选 PPPoE(路由器拨号)或 自动获取 IP(光猫拨号)
  4. 打开 DHCP-PD,让主路由正常下发 IPv6 前缀

这一步不需要做任何”指向旁路由”的操作——华硕也做不到。保持 IPv6 正常工作即可。

旁路由(ImmortalWRT)

第一步:让旁路由自己有 IPv6

旁路由自己要走 IPv6 出网、也要能被外网访问(NAS 穿透就靠它),所以要单独给它一个 WAN6 接口:

  1. 网络 → 接口 → 添加新接口
  2. 名称填 WAN6,协议选 DHCPv6 客户端
  3. 设备选 @lan(绑定到原有 LAN 口的别名)
  4. 提交后进入 WAN6 的高级设置,勾选 使用默认网关
  5. 在同一页的 DHCP 服务器 → IPv6 设置 里,把 RA 服务、DHCPv6 服务、NDP 代理 全部设为 已禁用

注意最后这一步:旁路由只”自己上网”,不负责给局域网发地址,否则就会和主路由抢着当 IPv6 网关,轻则断流,重则整网掉线。

第二步:过滤 AAAA(核心)

网络 → DHCP/DNS → 高级设置,勾选 过滤 IPv6 AAAA 记录(Filter IPv6 AAAA entries),保存并应用。

第三步:分流插件配合

在 OpenClash / HomeProxy / Passwall 里:

一个必须验证的前提

AAAA 过滤只对”把旁路由当 DNS“的终端生效。如果你的终端还在用主路由 RA 里下发的 IPv6 DNS(RDNSS),它会绕过旁路由直接问主路由要 AAAA,过滤等于没做。

验证方法很简单,在任意终端上:

nslookup ipv6.google.com

最后用 test-ipv6.com 验证结果:方案 A 下显示”未检测到 IPv6 地址”是正常的,不是配置失败。此时终端走 IPv4 出网、经旁路由分流,而旁路由自己有 IPv6,两边互不干扰。

方案 B:NAT6 强接管,让 IPv6 也走旁路由

如果你就是要终端跑真 IPv6(比如某些游戏、P2P、或者单纯不想让 IPv6 变成”残疾网络”),那就得让旁路由当 IPv6 网关,同时做 NAT6。

旁路由(ImmortalWRT)

1. LAN 口接管 IPv6 分配

网络 → 接口 → LAN → DHCP 服务器 → IPv6 设置:

为什么禁用 DHCPv6?因为安卓设备原生不支持有状态 DHCPv6,只认 SLAAC;两边都开,安卓会拿到两套地址和两个网关,直接打架。

2. NAT6 规则

ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

eth0 换成你旁路由实际对外的网口名(网络 → 接口里能看到)。

两个前置条件别漏:

3. 插件配置(以 OpenClash 为例)

方案 B 的代价

这就是为什么我更推荐 A:它把复杂度留给了 DNS,而不是路由。

隐藏的坑:硬件加速让防火墙规则”脱靶”

如果说前面是架构问题,那这一段就是纯粹的”玄学变科学”。

场景是这样的:Google TV 有有线和无线两张网卡,技术奇客ITGeeker.net在华硕主路由的 FORWARD 链里按 MAC 地址把两张网卡全 DROP 了,目的很简单——电视只能走 IPv4,老老实实经过旁路由的 OpenClash。结果呢?电视照样能连上 YouTube,画质卡死,代理完全没起作用。

原因不在规则写错,而在华硕的硬件加速。

Asuswrt 默认开启 Flow Acceleration(博通平台叫 Runner / Archer / Crossbow)。当一条连接的第一批包建立状态后,后续数据包由交换芯片直接转发,完全不经过 Linux 的 Netfilter。也就是说,等你的 FORWARD 规则生效时,电视的 IPv6 连接早就进了硬件流表,后面的包全都”合法”通过。

强制”无死角重解析”的四步

先把拦截规则插到链的最前面(用 -I 而不是 -A),再去清空流表和连接跟踪:

# 1. 插到最前面,双栈双链都拦
ip6tables -I FORWARD -m mac --mac-source b8:7x:d4:9c:35:26 -j DROP
ip6tables -I FORWARD -m mac --mac-source 1e:79:26:4d:44:31 -j DROP
ip6tables -I INPUT   -m mac --mac-source b8:7x:d4:9c:35:26 -j DROP
ip6tables -I INPUT   -m mac --mac-source 1e:79:26:4d:44:31 -j DROP

# 2. 清空硬件加速流表(新版固件用 fcctl,老版用 fc)
fcctl flush || fc flush

# 3. 清空连接跟踪,让旧连接全部重新走一遍慢路径
conntrack -F

两个细节:

命令执行完,必须把电视断电 10 秒再上电(或者在电视上”忘记 Wi-Fi 再连”)。不重启的话,电视端缓存的连接还会继续命中旧流表,看起来像”规则没生效”。

重启后,电视的所有新建 IPv6 握手都会撞上 INPUT/FORWARD 的死规则,IPv6 通道直接瘫痪,系统自动降级到 IPv4,这时候才真正走上旁路由的代理。

持久化:这里有个坑,别照抄就信

这个方案最大的问题是重启就没了。网上流传的做法是把脚本塞进 script_usbmount 这个 NVRAM 变量,让系统在挂载 U 盘时执行:

nvram set script_usbmount="/tmp/mnt/ASUSRouter/block_tv_ipv6.sh"
nvram commit

但要注意:较新的华硕官方固件已经会丢弃这个变量(社区从 2023 年的 388 固件起就有报告,值会被 asd 清掉,或者干脆不执行)。RT-BE88U 属于 3006.102 这一代,风险更高。

先做这个自检,别急着相信:

nvram set script_usbmount="/bin/touch /tmp/yesitworks"
sleep 15
nvram get script_usbmount   # 有输出 = 变量还在
ls -l /tmp/yesitworks       # 文件存在 = 钩子真的被执行了

如果 nvram get 为空、或者文件没出现,说明你的固件不吃这一套。可以选:

  1. 刷 Asuswrt-Merlin,用官方的 /jffs/scripts/post-mount 和 services-start 钩子,这是最干净的路子
  2. 用社区的 asusware-usb-mount-script 变通方案,借 Download Master 的挂载入口拉起 /jffs/scripts/usb-mount-script
  3. 干脆用一台常开的小主机(旁路由本身)定时 SSH 到主路由重放规则——最土,但最不容易被固件更新搞坏

不管用哪种,改完一定真的重启一次路由器验证,而不是看 nvram get 有值就以为成了。

最后,一份检查清单

  1. 终端 test-ipv6.com 有没有 IPv6 出口?有 → 分流大概率被绕过
  2. 终端在用的 DNS 是谁?不是旁路由 → AAAA 过滤等于没做
  3. 旁路由的 WAN6 拿到地址了吗?ifstatus wan6 或接口页看
  4. 主路由和旁路由是不是都在发 RA?是 → 只留一个
  5. 规则加了还是不生效?先怀疑硬件加速,清流表再试
  6. 重启后规则丢了?先验证 script_usbmount 到底有没有被执行

IPv6 是好东西,但在”主路由 + 旁路由”这种非标准架构里,它默认站在旁路由的对立面。想清楚自己要的是”分流生效”还是”终端必须有 IPv6″,剩下的就是选 A 还是选 B 的问题了。

退出移动版