
自定义x64路由器重启pppd后无法访问Google,IPv6委派成隐蔽故障点
来源标题:IPv6 delegation, an unusually subtle failure mode
用户的自定义x64 Linux路由器在重启pppd后无法访问Google,域名仍可解析但连接失败。诊断显示ping Google的IPv6地址2404:6800:4013:813::64出现100%丢包。问题指向IPv6委派,该故障模式较为隐蔽。
以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。
运行自定义 x64 路由器有很多好处。其一,它跑的是主线 Linux 内核,所以更新来得快。其二,路由器级别的广告拦截,不用多说了。其三,一旦出问题,你有机会深入进去,把毛病揪出来。
这周,我在自己的定制环境里经历了一段相当有意思的排查。我发现,只要我重启 pppd(负责连接 ISP 的那个进程),Google 就会变得不可访问——域名还能解析,但就是连不上。
图片来自 Jordan Harrison,发布于 Unsplash
诊断
我的这套环境里,networkd 负责整体网络管理,pppd 负责拨号连接 ISP,kea-dhcp4 负责分发 DHCPv4 地址,blocky 负责处理 DNS(路由器和笔记本上都跑着),而 RA 则由 networkd 自己处理。据我所知,这套栈里没有任何一处有问题。所有守护进程本身都久经考验,已知工作正常。
那问题会不会出在我的笔记本上?
~ ❯ ping -c 4 google.com PING google.com (2404:6800:4013:813::64) 56 data bytes --- google.com ping statistics --- 4 packets transmitted, 0 received, 100% packet loss, time 3064ms ~ ❯ ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host noprefixroute valid_lft forever preferred_lft forever 2: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether 00:00:5e:00:53:01 brd ff:ff:ff:ff:ff:ff inet 192.168.2.148/24 brd 192.168.2.255 scope global dynamic noprefixroute wlan0 valid_lft 4130sec preferred_lft 4130sec inet6 2001:db8:aaaa:1::10f1/64 scope global temporary dynamic valid_lft 3090sec preferred_lft 1290sec inet6 2001:db8:aaaa:1::1a03/64 scope global dynamic mngtmpaddr noprefixroute valid_lft 3090sec preferred_lft 1290sec inet6 2001:db8:bbbb:2::bea0/64 scope global temporary dynamic valid_lft 3554sec preferred_lft 1754sec inet6 2001:db8:bbbb:2::690f/64 scope global dynamic mngtmpaddr noprefixroute valid_lft 3554sec preferred_lft 1754sec inet6 fe80::5b9c/64 scope link noprefixroute valid_lft forever preferred_lft forever
一次 ping 就告诉我,Google 被解析到了它的 IPv6 地址,这洗清了 DNS 的嫌疑,但我 ping 不通那个地址。换成一个 IPv4 地址,却一切正常。
另一方面,wlan0 上出现了两组 IPv6 地址,而且较旧的那组 IPv6 地址,其 preferred lifetime 大于 0。这会不会就是罪魁祸首?我重启了 NetworkManager,结果你瞧,Google 奇迹般地恢复了,而我的 IPv6 地址也只剩下一组——新的那组。
我从没深入调试过网络,但这里的毛病似乎不难理解。每当 pppd 重启,它就会和我的 ISP 重新协商连接,ISP 会给路由器下发一个新的前缀用于委派。然而,没有任何设备会丢弃旧的 IPv6 地址。起初我以为是 NetworkManager 的锅,但后来我发现我的 iPhone 也有同样的表现。两个点构不成规律,但能连成一条线。这条线直指 networkd。
别误会,我喜欢 networkd。我的笔记本上之所以装 NetworkManager,只是因为它专为 Wi-Fi 和漫游设计,而且至今没让我失望过(iwd 万岁)。我的路由器和服务器跑的都是 networkd。它是个非常省心、不整幺蛾子的守护进程。所以我不太愿意怪它,于是转而去怪 pppd,算是给自己找个台阶下。
我决定确保在重新部署 NixOS 路由器时 pppd 永不重启。但不幸的是,有时候我的 ISP 会莫名其妙地抽风,pppd 自动重连,同样的问题就又回来了。这意味着我必须把这件事查个水落石出。
有意思的是,networkd 里有个 issue,标题是 RFC 7084 support in networkd (automatic ipv6 range delegation),2026 年 9 月有人在里面提出了正确实现 RFC 9096 的需求。同时还附了一个补丁,但至今尚未合并。同样的问题在 OPNsense 的 radvd 上也被提过,并以「not planned」关闭;dnsmasq 在 OPNsense 上也是如此。VyOS 的动态前缀支持至今仍是一个未关闭的功能请求。也就是说,那些常见的候选方案都出局了。只剩一个选择,而它在 NixOS 上还装不了——OpenWrt 的 odhcpd,它真正实现了 RFC 9096。
结果你瞧,当我故意重启 pppd 后,得到的是:
~ ❯ ip -6 addr show scope global 2: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP inet6 2001:db8:cccc:3::5286/64 scope global deprecated dynamic mngtmpaddr noprefixroute valid_lft 5325sec preferred_lft 0sec inet6 2001:db8:dddd:4::dcaa/64 scope global temporary dynamic valid_lft 5338sec preferred_lft 2638sec inet6 2001:db8:dddd:4::8a09/64 scope global dynamic mngtmpaddr noprefixroute valid_lft 5338sec preferred_lft 2638sec ~ ❯ ip -6 route get 2606:4700:4700::1111 2606:4700:4700::1111 from :: via fe80::1 dev wlan0 proto ra src 2001:db8:dddd:4::dcaa metric 100 pref medium ~ ❯ ping -6 -c3 2606:4700:4700::1111 3 packets transmitted, 3 received, 0% packet loss, time 2003ms rtt min/avg/max/mdev = 6.289/8.147/9.487/1.356 ms
成功了!最棒的一点是,odhcpd 的记忆在重启之后依然保留,而且不依赖你机器上设置的时间。这对我来说相当重要,因为我一直没换掉路由器上那块死掉的 CMOS 电池,每次路由器重启时钟都会归零。这让 odhcpd 能在每次重启后,以正确的 preferred/valid lifetime 0 来通告旧前缀,而完全不在意它们是什么时候被委派的。在实际场景中,如果我的路由器断电而 Wi-Fi 接入点仍然保持运行,或者我重启路由器(这绝对经常发生),这一点都会至关重要。考虑到家里人依赖家庭网络保持在线,我宁愿把所有情况都覆盖到。
(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。