Méthode efficace pour tester si le masque de réseau IPv6 au niveau du bit est contigu

J’ai besoin de stocker des adresses IP / masques de réseau dans une structure in_addr / in6_addr. Pour IPv4, j’utilise le code suivant pour tester si le masque de réseau est contigu:

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

Je me demandais s’il existe un moyen intelligent de faire de même pour IPv6.

Je suis tombé sur la solution suivante:

Divisez les octets IPV6 en quatre morceaux de 32 bits et créez trois parties de la manière suivante:

 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]; 

Si l'une de ces parties n'est pas contiguë, le masque de réseau n'est pas contigu.

  if ((((~address1 + 1) & (~address1)) != 0) || (((~address2 + 1) & (~address2)) != 0) || ((~address3 + 1) & (~address3)) != 0))) { // Netmask is not valid! } 

Certains compilateurs ont des entiers de 128 bits. J’ai utilisé __uint128_t dans un code qui a été compilé avec gcc sur une architecture AMD64.

Si vous utilisez un compilateur avec des entiers 128 bits, vous pouvez simplement réutiliser votre code existant, car il ne fait aucune hypothèse concernant la taille du mot.

Si vous devez effectuer le calcul avec une taille de mot plus petite, cela devient naturellement plus compliqué, mais pas beaucoup. Tout d’abord, passez un pointeur sur les mots du masque pour trouver le premier mot avec un bit de zéro (par exemple):

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

Ensuite, vous pouvez appliquer votre test d'origine au netmask[i] de netmask[i] . Enfin, vous devez vérifier que tous les mots restants sont nuls.

Une approche différente consiste à appliquer votre test initial à chaque mot et à vérifier que chaque paire de mots a le premier soit le premier ou le second le zéro.

 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; } 

Vous pouvez également adopter l'approche la plus commune et ne pas utiliser de masque en entrée, mais plutôt une longueur de préfixe spécifiée sous la forme d'un entier compris entre 0 et 128. Ensuite, vous pouvez construire vous-même le masque de masque et savoir qu'il est contigu.