如何在Linux中检测IPv6地址冲突
我了解到,在IPv6下IP地址冲突是极其罕见的。大多数子网至少有64位,这意味着真正随机碰撞的风险可以忽略不计。
然而,在某些情况下,真实的熵源非常有限(或损坏),风险会显著上升。我曾读到,在分配IP地址时,主机应使用邻居发现协议来检查该地址是否存在,如果存在则拒绝使用。
所以我的问题是:Linux在这种情况下会怎么做?如果我有一个软件想要向主机添加一个IP,该软件如何发现该IP已被占用?例如,使用ip命令行工具?
这个问题有两个角度让我不甚明了,导致我不愿依赖“在我的机器上可行”的方法来寻找答案:
- 语法的稳定性和输出的解析。
- 时序问题以及需要等待多长时间。
答案 1
内核在每次向接口添加IPv6地址时都会自动执行重复地址检测。程序无需做任何特殊操作来激活DAD。
如果我有一个软件想要向主机添加一个IP,该软件如何发现该IP已被占用。例如使用
ip命令行工具?
方法与添加IP地址相同:
如果程序使用Netlink(rtnl)——大多数Linux网络工具都是如此——那么在添加rtnl_addr对象后,它可以获取(RTM_GETADDR)同一个对象并检查其IFA_FLAGS:
- 存在
IFA_F_TENTATIVE意味着它仍在进行重复地址检测(实际上,除非启用了乐观DAD,否则内核不允许你使用它), IFA_F_DADFAILED意味着DAD完成并发现冲突(tentative标志也可能仍然存在),- 两个标志都不存在意味着DAD完成且未发现冲突。
程序不需要等待特定时间。内核的DAD代码已经有必要的计时器(这可能根据内核是否启用optimistic_dad或enhanced_dad而有所不同)。程序只需要持续检查(例如每秒一次),直到“tentative”标志消失或“dadfailed”标志出现,以先发生者为准。Netlink还提供变更通知(如ip monitor addr中所示),因此程序会自动在每次其标志更改时接收到地址对象,而无需任何轮询间隔。
如果程序使用ip命令行工具,那么首先,它应该停止使用ip命令行工具,开始使用为机器设计的接口,即Netlink。但如果这不可能,那么程序应使用ip -json来查询地址,将输出解析为JSON,并使用与Netlink相同的逻辑(即等待直到.tentative消失和/或.dadfailed出现)。
|
|
iproute2的ip命令行工具本身使用Netlink,所以它本身没有问题——它可以访问所有相同的信息,并且你可以手动运行它以检查相同的标志。但它首先是供人类使用的接口。
如果程序在没有-json选项的平台上使用ip命令行工具(可能是因为它是古老的iproute2版本,或者是Busybox的仿制品),那么很抱歉,这已经属于“在我的计算机上可行”的领域了。
如果程序使用旧的Linux 2.4时代的IPv6特定ioctl和/proc/net接口,那么据我所知,它无法获得此信息,应该移植到Netlink——尽管即使是ip -json也已经是升级了。(这特别包括net-tools的ifconfig,因为还没有人将其移植到现代Linux 2.6的方式。请避免使用net-tools。)
答案 2
我曾读到,在分配IP时,主机应使用邻居发现协议来检查IP是否存在并拒绝使用它。
是的,IPv6重复地址检测。基本上,你向一个特殊地址发送一个ICMPv6数据包,将:: IPv6作为源地址,然后你会得到稍后可以查询的信息(例如通过ip neighbor)。
但是:常见的连接建立工具会为你做这件事;例如,如果你用ip address add添加一个地址,你的系统将执行DAD,如果检测到冲突,分配将失败。(不过,你可以手动禁用此功能。)ip addr add --help是你的朋友 :)
评论:你能说得更具体点吗?当你说“IP地址分配将失败”时,命令会返回非零值/错误输出,还是我需要用另一个命令来检查?这确实是问题的关键。
回复:你试过吗?这真的可以在你的机器上无风险地尝试,一个接口可以有任意数量的IP地址,你可以尝试添加一个现有邻居的IP地址)。在你尝试添加冲突地址后,检查
ip addr show的内容!
回复:正如所说,你让Linux对它运行DAD,并检查
ip addr show的输出。这就是你的做法。(你也可以使用ip以外的其他用户空间工具读取接口地址属性,但这并不比读取ip更好。)
回复:(根据我现在阅读的RFC 2462,DAD不是幂等的:纯发送请求数据包会改变其他节点可能考虑的可用地址。因此,没有“无害的探测”。你真的应该在之后使用你请求的地址。)