PHP5 calcula o intervalo IPv6 a partir do prefixo cidr?

Posso fazer isso com o IPv4 usando fragments de código de várias fonts on-line. Eu queria saber se havia uma maneira de fazê-lo com o IPv6.

Basicamente eu só preciso de um formulário que eu possa inserir um endereço e prefixo IPv6 (ex: endereço / 68) e ele calcula o endereço de rede, o primeiro endereço utilizável, o último endereço utilizável e o endereço de transmissão. Então, apenas imprime na canvas. Não procurando armazená-lo em um database ou qualquer coisa ainda.

Como eu faria isso?

Graças a todos com antecedência!

Primeiro: o IPv6 não possui endereços de rede e broadcast. Você pode usar todos os endereços em um prefixo. Segundo: Em uma LAN, o comprimento do prefixo é sempre (bem, 99.x% do tempo) a / 64. O roteamento de um / 68 quebraria resources IPv6 como a configuração automática sem estado.

Abaixo está uma implementação detalhada de uma calculadora de prefixo IPv6:

< ?php /* * This is definitely not the fastest way to do it! */ // An example prefix $prefix = '2001:db8:abc:1400::/54'; // Split in address and prefix length list($firstaddrstr, $prefixlen) = explode('/', $prefix); // Parse the address into a binary string $firstaddrbin = inet_pton($firstaddrstr); // Convert the binary string to a string with hexadecimal characters # unpack() can be replaced with bin2hex() # unpack() is used for symmetry with pack() below $firstaddrhex = reset(unpack('H*', $firstaddrbin)); // Overwriting first address string to make sure notation is optimal $firstaddrstr = inet_ntop($firstaddrbin); // Calculate the number of 'flexible' bits $flexbits = 128 - $prefixlen; // Build the hexadecimal string of the last address $lastaddrhex = $firstaddrhex; // We start at the end of the string (which is always 32 characters long) $pos = 31; while ($flexbits > 0) { // Get the character at this position $orig = substr($lastaddrhex, $pos, 1); // Convert it to an integer $origval = hexdec($orig); // OR it with (2^flexbits)-1, with flexbits limited to 4 at a time $newval = $origval | (pow(2, min(4, $flexbits)) - 1); // Convert it back to a hexadecimal character $new = dechex($newval); // And put that character back in the string $lastaddrhex = substr_replace($lastaddrhex, $new, $pos, 1); // We processed one nibble, move to previous position $flexbits -= 4; $pos -= 1; } // Convert the hexadecimal string to a binary string # Using pack() here # Newer PHP version can use hex2bin() $lastaddrbin = pack('H*', $lastaddrhex); // And create an IPv6 address from the binary string $lastaddrstr = inet_ntop($lastaddrbin); // Report to user echo "Prefix: $prefix\n"; echo "First: $firstaddrstr\n"; echo "Last: $lastaddrstr\n"; ?> 

Ele deve produzir:

 Prefix: 2001:db8:abc:1400::/54 First: 2001:db8:abc:1400:: Last: 2001:db8:abc:17ff:ffff:ffff:ffff:ffff 

Para aqueles que se deparam com esta questão, você pode fazer isso de forma mais eficaz usando as funções dTRIP e dTRIP e a class dTRIP encontrada no GitHub .

Nós também notamos a falta de foco e ferramentas com o IPv6 em PHP, e juntamos este artigo, http://www.highonphp.com/5-tips , para o trabalho com wip6 , o que pode ser de ajuda aos outros.

Fonte de Função

Isso converte e IP para uma representação binária:

 /** * dtr_pton * * Converts a printable IP into an unpacked binary string * * @author Mike Mackintosh - mike@bakeryphp.com * @param string $ip * @return string $bin */ function dtr_pton( $ip ){ if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)){ return current( unpack( "A4", inet_pton( $ip ) ) ); } elseif(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)){ return current( unpack( "A16", inet_pton( $ip ) ) ); } throw new \Exception("Please supply a valid IPv4 or IPv6 address"); return false; } 

Isso converte uma representação binária em IP imprimível:

 /** * dtr_ntop * * Converts an unpacked binary string into a printable IP * * @author Mike Mackintosh - mike@bakeryphp.com * @param string $str * @return string $ip */ function dtr_ntop( $str ){ if( strlen( $str ) == 16 OR strlen( $str ) == 4 ){ return inet_ntop( pack( "A".strlen( $str ) , $str ) ); } throw new \Exception( "Please provide a 4 or 16 byte string" ); return false; } 

Exemplos

Usando a function dtr_pton você pode:

 $ip = dtr_pton("fe80:1:2:3:a:bad:1dea:dad"); $mask = dtr_pton("ffff:ffff:ffff:ffff:ffff:fff0::"); 

Obtenha sua Rede e transmissão:

 var_dump( dtr_ntop( $ip & $mask ) ); var_dump( dtr_ntop( $ip | ~ $mask ) ); 

E sua saída seria:

 string(18) "fe80:1:2:3:a:ba0::" string(26) "fe80:1:2:3:a:baf:ffff:ffff" 

Bem, para a posteridade, estou adicionando meu code aqui. E também como um agradecimento a vocês, que me ajudaram a pregar isso como eu precisava para um script ipv6 / ip2country .

É ligeiramente inspirado pelo código publicado aqui por @ mikemacintosh e @ Sander Steffann , um pouco melhorado (pensamento inteligente) e retorna um bom object que embala todos os dados que você faz / não precisa:

 /** * This: *  * Ipv6_Prefix2Range('2001:43f8:10::/48'); *  * returns this: *  * object(stdClass)#2 (4) { * ["Prefix"]=> * string(17) "2001:43f8:10::/48" * ["FirstHex"]=> * string(32) "200143f8001000000000000000000000" * ["LastHex"]=> * string(32) "200143f80010ffffffffffffffffffff" * ["MaskHex"]=> * string(32) "ffffffffffff00000000000000000000" * // Optional bin equivalents available * } *  * * Tested against: * @link https://www.ultratools.com/tools/ipv6CIDRToRange * * @param string $a_Prefix * @param bool $a_WantBins * @return object */ function Ipv6_Prefix2Range($a_Prefix, $a_WantBins = false){ // Validate input superficially with a RegExp and split accordingly if(!preg_match('~^([0-9a-f:]+)[[:punct:]]([0-9]+)$~i', trim($a_Prefix), $v_Slices)){ return false; } // Make sure we have a valid ipv6 address if(!filter_var($v_FirstAddress = $v_Slices[1], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)){ return false; } // The /## end of the range $v_PrefixLength = intval($v_Slices[2]); if($v_PrefixLength > 128){ return false; // kind'a stupid :) } $v_SuffixLength = 128 - $v_PrefixLength; // Convert the binary string to a hexadecimal string $v_FirstAddressBin = inet_pton($v_FirstAddress); $v_FirstAddressHex = bin2hex($v_FirstAddressBin); // Build the hexadecimal string of the network mask // (if the manually formed binary is too large, base_convert() chokes on it... so we split it up) $v_NetworkMaskHex = str_repeat('1', $v_PrefixLength) . str_repeat('0', $v_SuffixLength); $v_NetworkMaskHex_parts = str_split($v_NetworkMaskHex, 8); foreach($v_NetworkMaskHex_parts as &$v_NetworkMaskHex_part){ $v_NetworkMaskHex_part = base_convert($v_NetworkMaskHex_part, 2, 16); $v_NetworkMaskHex_part = str_pad($v_NetworkMaskHex_part, 2, '0', STR_PAD_LEFT); } $v_NetworkMaskHex = implode(null, $v_NetworkMaskHex_parts); unset($v_NetworkMaskHex_part, $v_NetworkMaskHex_parts); $v_NetworkMaskBin = inet_pton(implode(':', str_split($v_NetworkMaskHex, 4))); // We have the network mask so we also apply it to First Address $v_FirstAddressBin &= $v_NetworkMaskBin; $v_FirstAddressHex = bin2hex($v_FirstAddressBin); // Convert the last address in hexadecimal $v_LastAddressBin = $v_FirstAddressBin | ~$v_NetworkMaskBin; $v_LastAddressHex = bin2hex($v_LastAddressBin); // Return a neat object with information $v_Return = array( 'Prefix' => "{$v_FirstAddress}/{$v_PrefixLength}", 'FirstHex' => $v_FirstAddressHex, 'LastHex' => $v_LastAddressHex, 'MaskHex' => $v_NetworkMaskHex, ); // Bins are optional... if($a_WantBins){ $v_Return = array_merge($v_Return, array( 'FirstBin' => $v_FirstAddressBin, 'LastBin' => $v_LastAddressBin, 'MaskBin' => $v_NetworkMaskBin, )); } return (object)$v_Return; } 

Eu gosto de funções e classs e não gosto de código não reutilizável onde a funcionalidade reutilizável é implementada.

PS : Se você encontrar problemas com isso, fale de volta para mim. Estou longe de ser um especialista em IPv6.