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

我需要在in_addr / in6_addr结构中存储IP地址/网络掩码。 对于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位整数。 我在代码中使用了__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范围内的整数作为输入。 然后你可以自己构造位掩码并知道它是连续的。