我需要将 IP 地址/网络掩码存储在 in_addr/in6_addr 结构中。对于 IPv4,我使用以下代码测试网络掩码是否连续:
((((~netmask + 1) & (~netmask)) != 0) && (netmask != 0))
我想知道是否有一种聪明的方法可以为 IPv6 做同样的事情。
我需要将 IP 地址/网络掩码存储在 in_addr/in6_addr 结构中。对于 IPv4,我使用以下代码测试网络掩码是否连续:
((((~netmask + 1) & (~netmask)) != 0) && (netmask != 0))
我想知道是否有一种聪明的方法可以为 IPv6 做同样的事情。
我遇到了以下解决方案:
将 IPV6 字节拆分为四个 32 位的块,并按以下方式创建三个部分:
uint64_t netmask1, netmask2, netmask3;
netmask1 = (netmask.s6_addr32[0] << 32) + in6_netmask.s6_addr32[1];
netmask2 = (netmask.s6_addr32[1] << 32) + in6_netmask.s6_addr32[2];
netmask3 = (netmask.s6_addr32[2] << 32) + in6_netmask.s6_addr32[3];
如果其中一个部分不连续,则网络掩码不连续。
if ((((~address1 + 1) & (~address1)) != 0) ||
(((~address2 + 1) & (~address2)) != 0) ||
((~address3 + 1) & (~address3)) != 0))) {
// Netmask is not valid!
}
一些编译器有 128 位整数。我在使用 gcc 在 AMD64 架构上编译的代码中使用了 __uint128_t。
如果您使用的是 128 位整数的编译器,您可以简单地重用现有代码,因为它不对字长做任何假设。
如果你需要用更小的字长进行计算,它自然会变得更复杂,但并不多。首先通过掩码的字运行指针以找到第一个具有零位的字(例如):
for (i = 0; i < 4 && netmask[i] != 0xffffffff; ++i)
接下来您可以将原始测试应用于netmask[i]
,最后您需要测试任何剩余的单词是否为零。
另一种方法是将原始测试应用于每个单独的单词,并测试每对单词的第一个全为 1 或第二个全为零:
int contiguous(uint32_t **netmask)
{
int i;
for (i = 0; i < 4; ++i) {
if ((~netmask[i] + 1) & (~netmask[i])) return 0;
}
for (i = 0; i < 3; ++i) {
if ((netmask[i] != 0xffffffff) && (netmask[i+1] != 0)) return 0;
}
return 1;
}
您还可以采用更常见的方法,不将掩码作为输入,而是将前缀长度指定为 0 到 128 范围内的整数作为输入。然后您可以自己构建位掩码并知道它是连续的。