测试按位IPv6网络掩码是否连续的有效方法

时间:2014-12-27 14:03:34

标签: c bit-manipulation ipv6 netmask

我需要在in_addr / in6_addr结构中存储IP地址/网络掩码。 对于IPv4,我使用以下代码来测试网络掩码是否连续:

((((~netmask + 1) & (~netmask)) != 0)  && (netmask != 0))

我想知道是否有一种聪明的方法可以为IPv6做同样的事情。

2 个答案:

答案 0 :(得分:1)

有些编译器有128位整数。我在代码中使用了__uint128_t,这是在AMD64架构上使用gcc编译的。

如果您使用的是128位整数的编译器,则可以简单地重用现有代码,因为它不会对字大小做出任何假设。

如果你需要用较小的字大小进行计算,它自然会变得更复杂,但并不多。首先运行一个指针,通过掩码的字来找到第一个带有零位的字(例如):

for (i = 0; i < 4 && netmask[i] != 0xffffffff; ++i)

接下来,您可以将原始测试应用于netmask[i],最后您需要测试任何剩余的单词是否为零。

另一种方法是将原始测试应用于每个单词,并测试每对单词的第一个是全部的,或者第二个是全零:

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范围内的整数作为输入。然后你可以自己构造位掩码并知道它是连续的。

答案 1 :(得分:1)

我遇到了以下解决方案:

将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!
}