有 IPv6 地址却出不去:一次 iStoreOS ip6class 错配的完整定位
本文最后更新于:2026年11月9日 下午
家里网络最近使用 “My NAT” 和 “NatTypeTester” 工具测了下,发现家里的 NAT 类型是最差的一种 NAT 类型:NAT4 - ” 对称型 NAT“。如下图:

这种 NAT 网络穿透能力极差,必须进行优化。优化思路有这么几种:
- ❌ 找运营商要公网地址:试过了,不给
- ✅ 光猫改桥接:少一层 NAT 转换,会好很多
- ❌ 路由器配置优化,防火墙优化:测之前就已经优化过了,结果还是 NAT4 - ” 对称型 NAT“。证明跟这条没关系。
所以联系了运营商,这几天将光猫改为了桥接,用自己的路由器 - iStoreOS(基于 OpenWrt)拨号上网。改之后如下:


🎉🎉🎉好歹不是最差的了!
然后这几天才发现,改了后 Tailscale netcheck 里 IPv6 那行写着 no。5 台同局域网的机器,这一行都是 no。
查下来是个前缀委派错配,就是路由器拨号模式改了,但是 IPv6 相关配置没及时更新。
📝声明:文中公网 IPv6 前缀已做掩码处理,具体数值以
xxxx代替。
一、Tailscale 输出分析
IPv6: no, but OS has support。
这句很容易被读成「这台机器没有 IPv6」。实际上不是。
netcheck 在这一行背后至少看了三件事:
- 操作系统有没有 IPv6 能力、
- 能不能把包发出去、
- 能不能完成一次 STUN 往返。
用 tailscale netcheck --format json 看原始字段,5 台节点的结果完全一致:
| 字段 | 值 | 含义 |
|---|---|---|
OSHasIPv6 |
true | 系统有 IPv6 栈 |
IPv6CanSend |
true | 有默认路由,包能发出去 |
IPv6 |
false | 一次 STUN 往返都没完成 |
GlobalV6 |
空 | 没探到可用的全局地址 |
IPv6CanSend 对应的是:
ip -6 addr里有全局地址(SLAAC 分到的 /64),ip -6 route show里有 default。
这两条都满足,它就是 true。
二、证据链:从 0.5ms 到黑洞
逐条测试排查:
- 局域网内正常:ping 路由器和同网段节点,0.5ms,0% 丢包。
traceroute6到2400:xxxx::1:第 1 跳是路由器,第 2 跳开始全是*。tcpdump:只看到 echo request 出去,没有任何 ICMPv6 错误回来。- 在路由器上分源 ping6:路由器自身 ping6 正常,用 WAN 源 ping6 正常,用 LAN 源 ping6 100% 丢包。
到第 4 步,问题范围已经从「运营商」收缩到「路由器内部的 LAN 转发路径」。
再看出口设备:
1 | |
输出里出口是 via fe80::1 dev eth1。
eth1 是裸物理口,不是 pppoe-wan。LAN 的 IPv6 流量被扔进了一个没有 PPPoE 封装的接口,出去了也没人接。
三、根因:三个 uci 项凑出来的错配
📝Notes:这一段是 iStoreOS / OpenWrt 的 uci 配置,其他系统的对应项名字不同,机制类似。
运营商的 PD 是 240e:xxxx:xxxx:xxxx::/60(具体前缀已掩码),也就是 16 个 /64。
LAN 上实际用的却是另一个 240e:xxxx:xxxx:xxxx::/64,压根不在上面这 16 个 /64 里。
三个 uci 项共同造成这个结果:
network.lan.ip6class='wan6':LAN 只接受wan6这个接口提供的前缀。而wan6绑在裸eth1上,不是 PPPoE 那个wan_6。主因。(⚠️:PPPoE 之前,WAN 口叫作wan6- 没有下划线;PPPoE 之后,WAN 口叫作wan_6- 有下划线)network.wan.delegate='0':禁止把 PPPoE 拿到的 /60 委派给 LAN。network.wan6.device='eth1':多出来的一个 DHCPv6 客户端,绑在物理口上。
三项叠加,LAN 就拿着一个不在委派段里的 /64,配上一个指向裸 eth1 的默认路由。
四、修复与验证
- 备份
/etc/config/network。 uci set network.lan.ip6class='wan_6'。uci set network.wan.delegate='1'。uci commit,然后ifup lan。- 验证三处:
ip -6 addr show br-lan,看前缀是否落在运营商的 /60 里;ubus call network.interface.wan_6 status,看委派前缀;uci get network.lan.ip6class,核对 class 是否匹配。
- 确认生效后,
network.wan6.disabled='1',再ifup wan6。
修复后 LAN 前缀变成 240e:xxxx:xxxx:xxxx::/64,默认路由走 pppoe-wan。
netcheck 从 IPv6: no 变成 IPv6: yes。如下图:
1 | |
ping6 从 100% 丢包变成 AliDNS 13.8ms。
手机(有 IPv6 地址)打开 Tailscale,可以 100% 稳定直连到家里的 Tailscale 其他设备。如下图:

五、最容易漏的一步:客户端旧地址
路由器修好了,客户端 netcheck 可能还是 no。
原因是 SLAAC 分下来的旧地址 valid_lft 还有大约 90 分钟,内核做源地址选择时仍然可能挑中那个旧前缀。
手工清一下:
1 | |
这一步漏掉,会得到「配好了但没用」的错觉。
六、附带发现:CGNAT 与打洞
排查过程中顺手看了下 pppoe-wan,地址是 100.x.x.x/32,落在 100.64.0.0/10 这个 RFC 6598 定义的共享地址空间(Shared Address Space)里。
也就是说我这条电信宽带没有公网 IPv4。
路由器上 miniupnpd 报 IGNORED: private/reserved address 不是故障,端口转发本来就到不了公网,PortMapping 里 UPnP 永远无法正常发挥作用。
这个 CGNAT 是 cone 型(具体是端口限制锥形)(MappingVariesByDestIP: false),IPv4 打洞依然能成,所以修复之前,基于 IPv4 直连没彻底断 - 时灵时不灵。
要根治还是两条路:
- ✅ 把 IPv6 修好(已经做了),
- ❌ 或者向电信申请公网 IP - 不可能做到
另外电信每次重拨都会换 PD 前缀,这次 PD 前缀发生了变更(具体前缀已掩码)。属正常现象,配置写进 uci 之后 LAN 会自动跟随,不用每次手动改。
七、五步排查顺序
整理成可复用的顺序,下次换台设备也能照着走:
ip -6 addr/ip -6 route show:有没有全局地址、有没有默认路由。traceroute6 2400:xxxx::1:第几跳开始静默。第 1 跳死是局域网问题,第 2 跳死是网关问题。- 上路由器
ping6 -I <WAN地址> <公网v6>:判断 ISP 侧通不通。 ip -6 route get <公网v6> from <LAN地址>:看出口 dev 是不是pppoe-wan或wan。ubus call network.interface.wan_6 status加uci get network.lan.ip6class:核对委派前缀与 LAN 前缀、class 是否匹配。
总结
IPv6: no, but OS has support 的迷惑性在于它把三件事压成了一行:系统能力、发包能力、连通性。
前两个 true,第三个 false,输出就成了一个 no。
把三件事拆开,再用 ip -6 route get ... from ... 定位出口设备。
iStoreOS 上的 ip6class、delegate、wan6.device 三个项互相牵连,只改一个不够。改完记得清客户端旧地址,旧地址的 valid_lft 没走完之前,客户端可能一直拿着旧前缀。
以上。