跳到内容
观澜涉川 · 札记EN

OpenWrt 二级路由开启 IPv6 中继(Relay)模式:让内网设备拿到公网 IPv6

· 约 4 分钟阅读

最近中国联通使用断网逼迫的手段,硬给家里换了一台光猫,之后发现再也无法通过 Tailscale 连接到家里的内网设备了(偶尔可以用过 Relay 的方式建立连接,但是太慢了)。最近 AI模型都降价了,原本可以在外边连回家里,蹬各种 AI 模型来干活,结果被联通的搞坏了。投诉无门,只能自求多福。后来偶尔发现,居然可以用手机通过 4G/5G 网络访问家里的内网设备。经过排查发现,Tailscale 可使用 IPv6 建立 Direct Connection。所以,只要让内网设备拿到公网 IPv6 地址,也许就从外部访问了。遗憾的是,工作电脑在二级路由上,并没有开启 IPv6。最后发现,可以通过在二级路由上开启 IPv6 中继(Relay)模式,让内网设备获取公网 IPv6 地址。

案情梳理:谁偷走了我的 IPv6

先交代一下家里的网络结构,方便各位看官理解这场闹剧:

  • 一级路由(家用路由):IPv6 设置里的“前缀授权”只有“自动”和“关闭”两个选项,没有“手动指定长度”或“下发至下级”。于是它就从运营商拿到 PD 前缀,自己独吞,绝不往下发。
  • OpenWrt 二级路由:接在一级路由下面,想要前缀,要不到。
  • 工作电脑:接在二级路由下面,嗷嗷待哺,只有一个 fe80:: 链路本地地址。

换光猫之前,一切岁月静好。换完之后,Tailscale 从大概率可以建立成功的 Direct Connection 退化成 Relay,再退化成直接连不上。排查过程就不细说了,无非是 ping6、traceroute、看日志、骂运营商、再看日志。最终定位到问题:一级路由不下发 IPv6 前缀,导致二级路由无法获取到公网 IPv6,进而内网设备也无法获取公网 IPv6。

解法:让二级路由放弃治疗,改做中继

既然从一级路由那里要不到前缀,那就换个思路:二级路由不做独立的 IPv6 路由器了,改行当快递员,把一级路由的 RA / DHCPv6 / NDP 消息原样透传给内网设备。

这就是 IPv6 中继(Relay)模式。设备拿到的地址直接来自一级路由,网关也指向一级路由,二级路由只在中间当一根透明的管子。

准确地说:IPv4 流量由二级路由做 NAT 转发,IPv6 流量则绕过二级路由的三层路由,由一级路由统一分配地址并担任网关。二级路由在 IPv6 这一层退化成了二层交换机。

配置步骤(LuCI 界面)

  1. 配置 LAN 接口:进入“网络” → “接口” → “LAN” → “编辑” → “DHCP 服务器” → “IPv6 设置”,将“路由通告服务(RA-Service)”,“DHCPv6 服务(DHCPv6-Service)”和“NDP 代理(NDP-Proxy)”都设置为“中继模式 (relay mode)”。
  2. 配置 WAN6 接口:进入“网络” → “接口” → “WAN6” → “编辑” → “DHCP 服务器” → “IPv6 设置”,保持“忽略此接口”为勾选状态,将“路由通告服务”“DHCPv6 服务”“NDP 代理”都设置为“中继模式”,并勾选“指定的主接口”。

重连客户端

断开 Wi-Fi 重连,或者重启网络接口,或者就是等几秒。别问,问就是玄学。

见证奇迹的时刻

中继配置完成后,先确认你的设备到底有没有拿到公网 IPv6:

Terminal window
ifconfig | grep inet6

成功的话,你会看到类似这样的输出:

inet6 2408:xxxx:xxxx:xxxx:3df1:6840:829a:d770/64 scope global temporary dynamic
valid_lft 86234sec preferred_lft 14234sec
inet6 2408:xxxx:xxxx:xxxx:8b7a:eda:506c:ce6c/64 scope global dynamic mngtmpaddr noprefixroute
valid_lft 86234sec preferred_lft 14234sec

重点是:

  • 2408: 开头:说明是联通公网 IPv6 段,不是 fe80:: 链路本地,也不是 fd00:: ULA。
  • scope global:全球可路由。
  • temporary dynamic:隐私扩展地址,对外通信用的就是它,会定期更换。
  • mngtmpaddr:稳定模板地址,系统用它来生成临时地址。
  • 注意 preferred_lft 是首选期,过了之后系统会生成新的临时地址,旧地址逐渐弃用。这就是临时地址会变的原因。

如果只看到 fe80:: 开头的地址,说明中继没生效,回去检查配置。

测试连通性

Terminal window
ping6 -c 3 240c::6666

这是联通公共 DNS。通了就说明 IPv6 出海正常。

再访问 https://test-ipv6.com 看评分。如果不再是 0/10,恭喜,可以从外网直连回家了。

原理简析

中继模式下,二级路由不自己分配地址,而是把一级路由的 RA、DHCPv6、NDP 消息原样转发到 LAN 侧。设备收到的 RA 里,前缀来自一级路由,网关也指向一级路由的链路本地地址。

二级路由的角色从“路由器”退化成了“二层交换机”,只不过它还保留了防火墙和 IPv4 路由的功能。某种意义上,这是一种降级,但在拿不到 PD 前缀的情况下,这是最优雅的解法。

注意事项

中继打破了 NAT 隔离,运营商和一级路由都能看到每台设备的公网 IPv6 地址。介意的话,对不需要外网的设备用 ULA fd00::/8。

不过说实话,在联通硬塞光猫的前提下,你的隐私早就不是你能控制的了。呵呵。

结果:Tailscale 复活

配置完成后,在 4G/5G 网络下,Tailscale 从 Relay 切换回 Direct Connection,延迟从 Relay 时的几百毫秒甚至上千毫秒,降到直连时的几十毫秒以内。AI 模型终于可以顺畅地蹬了,钱包表示压力很大。

一句话总结

OpenWrt 二级路由拿不到 PD 前缀时,把 LAN 和 WAN6 的 RA / DHCPv6 / NDP 全部设为 relay mode,并在 WAN6 勾选“指定的主接口”,即可让内网设备直接获得上游分配的公网 IPv6 地址。