Canary Workshop

ここから始めよう 世界を見にゆこう

记录一次 IPv6 DAD 导致的诡异网络故障

这是一台运行 Arch Linux 的服务器,在一次日常滚系统后网络挂掉,检查到最后发现是 DAD 的问题。感觉解决问题的过程有必要记录下来。

这台服务器的网络由 systemd-networkd 托管,IP 地址和网关直接写死在 /etc/systemd/network/default.network 中。长久以来,这个配置都工作良好。今天(其实是昨天了)一次很日常的 sudo pacman -Syu 重启后网络却挂掉了,那就开修吧

所以深夜出现这种情况真的会拉高血压

首先第一反应是滚挂了系统根本没起来。进入 Console 发现系统启动是没问题的,登录进去检查,发现网卡配置也正常,IP 地址也已经被附加到网卡上,但很明显上不了网。

那么问题很明显就是路由表了。ip route 查看路由,发现果然不存在缺省路由,难怪连不上。Console 操作毕竟不舒服,先手动加个 IPv4 路由吧,SSH 进去慢慢检查。

然而,在经过各种修改配置文件后,却发现无论如何都不能自动加上路由就差把 ip route 写进启动执行了,使用 ip monitor 也发现,在 sudo systemctl restart systemd-networkd 的一瞬间,路由被删了,再也没加回来。

执行 networkctl,发现一点端倪:ens3 那一栏状态是 configuring ,也就是说一直配置不好。回想到 ip monitor 里偶尔会有 FAILED [IPv6地址]的报错,有没有可能是 IPv6 地址无法配置,导致整个网卡配置不成功?

那就如法炮制,给 IPv6 手动加上默认路由试试吧。加路由这一步没有报错,但是完全无法连上外网,甚至无法 ping 通网关。再进(近?)一步,发现本机 IPv6 也不能 ping 通。执行 ip route get [IPv6地址],更诡异的一幕出现了:src 字段居然是一个私有地址。原来如此,公网 IPv6 根本就没有用在路由表里,也不可能通向外网了。

可是明明记得 ip address 中存在公网 IPv6,再运行一次仔细看看,终于发现了盲点:IPv6 的部分赫然写着 scope global dadfailed tentative

DAD 全称 Duplicate Address Detection,是 IPv6 检测地址冲突的机制。也就是说,我本机的 IPv6 和网内其他地址冲突了?不管怎样,最要紧的是先恢复网络。于是修改 /etc/sysctl.d/99-sysctl.conf 并加入:

1
net.ipv6.conf.ens3.accept_dad = 0

重启,世界恢复平静。

不过,一直没想明白的是,为什么会发生这个问题?这个服务器托管在世界上最大的云服务商之一,网络隔离非常严格,况且按理来讲不太可能有人故意设置我的地址……

但总之能用了,睡觉