iStoreOS IPv6 NDP Relay 模式故障排查与修复
iStoreOS IPv6 NDP Relay 模式故障排查与修复
Mac 有 IPv6 地址却 ping 不通任何公网 IPv6。之前一直正常,某天突然全断,重启路由器也没用。最终定位是 iStoreOS 的 NDP Relay 模式不稳定,改一行配置从 relay 切到 server 就修好了。这篇记录了逐层排查到根因的完整过程。
环境
| 项目 | 值 |
|---|---|
| 宽带运营商 | 中国移动 |
| 光猫 | 华为 HN8546X6N-20(10G-GPON HGU) |
| 光猫地址 | 192.168.1.1 |
| 路由器 | iStoreOS(OpenWrt 衍生固件) |
| 路由器地址 | 192.168.100.1 |
| 客户端 | macOS(Mac mini) |
网络拓扑
中国移动物联网 100.107.64.1
↓
光猫 华为HN8546X6N-20 (192.168.1.1)
│ WAN侧前缀: 2409:8a00:26c6:8e0::/64(通过 RA 广播)
│ PD委派前缀: 2409:8a00:26c6:8e1::/64(通过 DHCPv6-PD 给路由器)
↓
iStoreOS 路由器 (192.168.100.1)
│ eth0 (WAN): 2409:8a00:26c6:8e0::1
│ br-lan (LAN): 2409:8a00:26c6:8e1::1
↓
Mac (192.168.100.x)
网卡: en8(有线)
代理: xray (socks5://127.0.0.1:10808)故障现象
| 现象 | 详情 |
|---|---|
| Mac 有 IPv6 地址 | 2409:8a00:26c6:8e0:xxxx(SLAAC 分配) |
| ping6 任何公网 IPv6 | 100% 丢包 |
| SSH 到 IPv6 VPS | 超时 |
| 通过代理连 VPS SSH | 可以通(代理服务器有独立 IPv6 出口) |
| 路由器重启 | 无效 |
逐层排查(分而治之)
核心方法是逐段测试,找出哪一段断了。
Step 1: 确认本地有 IPv6 地址
ifconfig en8 | grep "inet6"inet6 2409:8a00:26c6:8e0:877:d5df:d03a:f9f1 prefixlen 64 autoconf secured
inet6 2409:8a00:26c6:8e0:6de7:3f2:87ad:12 prefixlen 64 autoconf temporaryMac 有中国移动 SLAAC 分配的公网 IPv6 地址。但有地址不代表连通性正常。
Step 2: 确认 IPv6 确实不通(排除代理干扰)
# ping6 是 ICMP,完全不受 HTTP_PROXY/ALL_PROXY 影响
/sbin/ping6 -c 3 2606:4700:4700::11113 packets transmitted, 0 packets received, 100.0% packet loss直连 IPv6 完全不通,不是代理问题,是路由层面的问题。
Step 3: 逐段测试定位断点
Mac → 公网 IPv6 → ❌ 100% 丢包
Mac → iStoreOS (link-local) → ✅ 1.6ms
iStoreOS → 光猫 fe80::1 → ✅ 1.5ms
iStoreOS → 公网 IPv6 → ✅ 198ms# Mac → 路由器(link-local,需要 zone ID)
/sbin/ping6 -c 2 fe80::447b:bcff:fe7d:cde4%en8
# iStoreOS → 光猫
ssh [email protected] "ping6 -c 3 -I eth0 fe80::1"
# iStoreOS → 公网
ssh [email protected] "ping6 -c 3 2606:4700:4700::1111"iStoreOS 以上全通,问题在 iStoreOS → Mac 的 IPv6 转发,路由器的 IPv6 配置有问题。
Step 4: 检查 iStoreOS 的 IPv6 工作模式
ssh [email protected] "uci show dhcp | grep -E 'ra|dhcpv6|ndp'"dhcp.lan.ra='relay'
dhcp.lan.dhcpv6='relay'
dhcp.lan.ndp='relay'
dhcp.wan.ra='relay'
dhcp.wan.dhcpv6='relay'
dhcp.wan.ndp='relay'iStoreOS 使用 NDP Relay(中继)模式。Relay 模式不稳定是已知问题,可能是根因。
Step 5: 重启 odhcpd 无效
ssh [email protected] "/etc/init.d/odhcpd restart"
sleep 5
/sbin/ping6 -c 3 2606:4700:4700::1111
# 仍然 100% 丢包Relay 模式本身有缺陷,不能简单通过重启修复。
Step 6: 关键突破 — 检查光猫是否给了前缀委派(PD)
排查的转折点:搞清楚光猫到底有没有给 iStoreOS 独立的 IPv6 前缀。
先看 WAN 接口,没发现 PD:
ssh [email protected] "ubus call network.interface.wan status"{
"proto": "dhcp",
"delegation": false,
"ipv6-address": [],
"ipv6-prefix": []
}WAN 是纯 IPv4 DHCP,delegation 也关了。看起来光猫没给 PD。但 iStoreOS 原始配置里还有一个独立的 DHCPv6 接口(proto=dhcpv6, device=eth0):
ssh [email protected] "ubus call network.interface.DHCPv6 status"{
"proto": "dhcpv6",
"up": true,
"delegation": true,
"ipv6-prefix": [
{
"address": "2409:8a00:26c6:8e1::",
"mask": 64,
"class": "DHCPv6",
"assigned": {
"lan": {
"address": "2409:8a00:26c6:8e1::",
"mask": 64
}
}
}
],
"route": [
{"target": "::", "nexthop": "fe80::1",
"source": "2409:8a00:26c6:8e1::/64"}
]
}光猫通过 DHCPv6-PD 成功委派了 /64 前缀(2409:8a00:26c6:8e1::/64)给 iStoreOS,且已分配给 LAN。iStoreOS 有自己的公网前缀,完全可以做原生 IPv6 路由,不需要 relay,更不需要 NAT。Relay 模式纯属多余。
Step 7: 改 DHCP 为 Server 模式
ssh [email protected] 'bash -s' << 'EOF'
# 先备份
cp /etc/config/dhcp /etc/config/dhcp.bak.$(date +%Y%m%d_%H%M%S)
# LAN 从 relay 改为 server
uci set dhcp.lan.ra='server'
uci set dhcp.lan.dhcpv6='server'
uci set dhcp.lan.ndp='disabled'
uci set dhcp.lan.ra_management='1'
# WAN / DHCPv6 接口的 relay 全部关闭
uci set dhcp.wan.ra='disabled'
uci set dhcp.wan.dhcpv6='disabled'
uci set dhcp.wan.ndp='disabled'
uci set dhcp.DHCPv6.ra='disabled'
uci set dhcp.DHCPv6.dhcpv6='disabled'
uci set dhcp.DHCPv6.ndp='disabled'
uci commit dhcp
/etc/init.d/odhcpd restart
EOFStep 8: 清除 Mac 旧的 IPv6 缓存地址
Mac 上还缓存着 relay 透传的旧 8e0 段地址(WAN 侧前缀),会导致源地址选错:
# 删除旧地址
sudo ifconfig en8 inet6 delete 2409:8a00:26c6:8e0:877:d5df:d03a:f9f1
sudo ifconfig en8 inet6 delete 2409:8a00:26c6:8e0:6de7:3f2:87ad:12删除后 Mac 只保留 8e1 段(正确的前缀)的地址。
Step 9: 验证
# Mac IPv6 地址(纯公网 8e1 段)
ifconfig en8 | grep "inet6.*global"
# inet6 2409:8a00:26c6:8e1:143d:241d:4659:ace5
# ping6 Cloudflare
/sbin/ping6 -c 3 2606:4700:4700::1111
# 3 packets transmitted, 3 received, 0% loss, 199ms原生 IPv6 全通,端到端直连。
配置改动对照表
| 配置项 | 修改前 | 修改后 | 说明 |
|---|---|---|---|
dhcp.lan.ra | relay | server | iStoreOS 自己发 RA |
dhcp.lan.dhcpv6 | relay | server | iStoreOS 自己分配 IPv6 |
dhcp.lan.ndp | relay | disabled | 不需要 NDP 代理 |
dhcp.lan.ra_management | (无) | 1 | RA 携带前缀 + 管理 flag |
dhcp.wan.ra | relay | disabled | WAN 不参与 |
dhcp.wan.dhcpv6 | relay | disabled | WAN 不参与 |
dhcp.wan.ndp | relay | disabled | WAN 不参与 |
根因分析
NDP Relay 模式的工作原理
NDP(Neighbor Discovery Protocol)是 IPv6 的核心协议,相当于 IPv4 的 ARP,设备通过它发现同一网段内的邻居和路由器。
在标准 IPv6 路由模式下,光猫通过 DHCPv6-PD 给路由器一个前缀,路由器再广播给 LAN,每层有不同的前缀:
光猫 ──PD委派──→ iStoreOS ──RA广播──→ LAN设备
8e0::/64 8e1::/64(独立前缀)但当光猫只给一个 /64、不做 PD 时,路由器没有自己的前缀分给 LAN,只能用 Relay 模式充当"传话筒",把光猫的 RA 和 NDP 消息原封不动中继到 LAN,LAN 设备和光猫逻辑上在同一个 /64 网段:
光猫 ──RA/NDP──→ iStoreOS ──中继RA/NDP──→ LAN设备
8e0::/64 8e0::/64(同一个前缀透传)为什么 Relay 不稳定
odhcpd进程需要持续中继光猫和 LAN 设备之间的 NDP 消息。- odhcpd 重启后会话断裂。
- 光猫 RA 间隔超时后中继链路断开。
- 断了之后不会自动恢复。
结果:LAN 设备拿到了 IPv6 地址(之前中继成功的缓存),但 NDP 邻居发现已失效,设备不知道该把包发给哪个 MAC 地址,包全部丢弃。
为什么 Server 模式能解决
本案中光猫实际给了 PD 前缀(2409:8a00:26c6:8e1::/64),通过独立的 DHCPv6 接口获取。改用 Server 模式后,iStoreOS 自己生成 RA 广播 8e1::/64 前缀,LAN 设备通过 SLAAC 获取 8e1 段地址,包通过默认路由 default from 2409:8e1::/64 via fe80::1 出去,端到端原生 IPv6 路由,无 NAT。
IPv6 三种模式对比
| 模式 | ra | dhcpv6 | ndp | 适用场景 | 稳定性 |
|---|---|---|---|---|---|
| Server(推荐) | server | server | disabled | 光猫给了 PD 前缀 | 最稳定 |
| Relay(默认) | relay | relay | relay | 光猫只给 /64,不给 PD | 不稳定 |
| NAT6(不推荐) | server | server | disabled | 光猫完全不支持 IPv6 | 丢失端到端 |
如何判断光猫是否给了 PD 前缀
# 检查 DHCPv6 接口的 PD 状态
ssh [email protected] "ubus call network.interface.DHCPv6 status" | grep -A5 ipv6-prefix
# 有 address + mask → 光猫给了 PD
# 空 [] → 光猫没给 PD
# 或检查 br-lan 是否有独立于 WAN 的前缀
ssh [email protected] "ip -6 addr show br-lan | grep 'scope global'"
# br-lan 前缀(如 8e1)≠ eth0 前缀(如 8e0)→ PD 成功踩坑记录
macOS ping6 语法和 Linux 不同
# ✅ 正确(link-local 需要 zone ID 指定接口)
ping6 fe80::xxx%en8
# ❌ macOS ping6 不支持 -6 参数,也不支持 -b 指定源地址
ping6 -6 fe80::xxxIPv6 源地址选择(RFC 6724)
当 Mac 同时有多个 IPv6 地址时,系统按 RFC 6724 规则选择源地址。如果旧地址已失效但优先级更高(比如 relay 缓存的 8e0 段地址),Mac 会选错源地址,导致包发出去但回不来。解决办法是手动删除旧地址,或等待 valid_lft 过期。
NAT6 MASQUERADE 与本机服务端口冲突
NAT6 的 MASQUERADE 模式下,如果路由器本机也监听目标端口(如 SSH 22),内核处理转发包时可能把包交给本机服务而不是转发出去。现象是 ssh root@<VPS-IPv6> 返回的是路由器自己的 hostname。解决办法是不用 NAT6、用原生路由,或改路由器本机 SSH 端口。
默认路由的 source 限制
IPv6 默认路由可以带 from 限制:default from 2409:8a00:26c6:8e1::/64 via fe80::1 dev eth0,只有源地址属于 2409:8e1::/64 的包才走这条路由。如果 LAN 设备源地址不匹配,需要额外添加路由或删除旧地址。
ping6 通但 TCP 不通
如果 ping6(ICMP)通但 curl/nc(TCP)不通,检查:代理软件(xray TUN 模式可能劫持 TCP 流量但不影响 ICMP)、路由器 ip6tables FORWARD 链是否放行 TCP、用 python3 socket 测试(完全不走代理环境变量)。
经验总结
- IPv6 有地址 ≠ 能通信。SLAAC 分配了地址只代表 RA 到达过,不代表 NDP 邻居发现和路由都正常,始终用
ping6验证。 - 逐层排查是核心方法。Mac → 路由器 → 光猫 → 公网,逐段测试,快速定位断点在哪一层。
- 先查 PD 状态,再决定模式。
ubus call network.interface.DHCPv6 status是判断光猫是否给了前缀委派的关键命令。有 PD 用 Server 模式,没 PD 才考虑 Relay 或 NAT6。 - Relay 模式是已知坑。OpenWrt 的 odhcpd NDP Relay 不稳定是社区公认问题,能避免就避免。
- NAT6 是最后的手段,不是首选。IPv6 的设计理念是端到端直连,NAT6 虽然能工作但引入额外问题。
- ping6 不受代理影响。
HTTP_PROXY/ALL_PROXY只对 HTTP/curl 生效,ping6(ICMP)和python3 socket不受影响,是验证真实直连状态的最佳工具。 - 修改配置前务必备份。
cp /etc/config/dhcp /etc/config/dhcp.bak.$(date +%Y%m%d_%H%M%S),出了问题可以秒回滚。
