2012-04-10 12 views
5

Ich bin in der Lage, dies mit IPv4 mit Code-Schnipsel aus verschiedenen Online-Quellen zu tun. Ich habe mich gefragt, ob es einen Weg gibt, es mit IPv6 zu machen.PHP5 berechnen IPv6-Bereich von CIDR-Präfix?

Im Grunde brauche ich nur ein Formular, dass ich eine IPv6-Adresse und ein Präfix eingeben kann (ex: Adresse/68) und berechnet die Netzwerkadresse, erste verwendbare Adresse, letzte verwendbare Adresse und Broadcast-Adresse. Dann wird nur auf dem Bildschirm gedruckt. Ich suche nicht, um es in einer Datenbank oder noch etwas zu speichern.

Wie würde ich das machen?

Danke an alle im Voraus!

Antwort

5

Zunächst einmal: IPv6 hat keine Netzwerk- und Broadcast-Adressen. Sie können alle Adressen in einem Präfix verwenden. Zweitens: In einem LAN ist die Präfixlänge immer (naja, 99.x% der Zeit) a/64. Routing a/68 würde IPv6-Funktionen wie die zustandslose automatische Konfiguration unterbrechen.

Unten finden Sie eine ausführliche Implementierung eines Rechners IPv6-Präfix:

<?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"; 

?> 

Es Ausgabe sollte:

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

Genau was ich brauchte !!. Ich habe tagelang versucht, meinen Kopf darum zu wickeln, und ich bin gerade in einem Cisco-Kurs, aber wir haben noch nicht IPv6 erreicht und versuchen, das Konzept selbst zu verstehen. Ich habe mir den Code angeschaut, wie viel Code müsste geändert werden, wenn ich auch die zweite IP und die IP kurz vor der letzten hätte? Ich habe versucht, es herauszufinden, aber außerhalb meines Bereichs von PHP-Wissen :( – Damainman

+0

Nun, die zweite Adresse hat eine 1 anstelle von 0 als letztes Zeichen, und die vorletzte hat ein e anstelle von f. –

+0

PS : wenn du die antwort magst dann bitte als akzeptiert markieren :-) –

2

Für diejenigen, die auf diese Frage stolpern, können Sie dies effektiv die dtr_pton mit mehr tun und dtr_ntop Funktionen und dTRIP Klasse gefunden auf GitHub.

Wir haben auch einen Mangel an Fokus und Tools mit IPv6 in PHP festgestellt, und stellen Sie diesen Artikel, http://www.highonphp.com/5-tips-for-working-with-ipv6-in-php, die anderen helfen können.

Funktion Quelle

Dieser wandelt und IP in eine binäre Darstellung:

/** 
* dtr_pton 
* 
* Converts a printable IP into an unpacked binary string 
* 
* @author Mike Mackintosh - [email protected] 
* @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; 
} 

Dieser wandelt eine binäre Darstellung in druckbare IP:

/** 
* dtr_ntop 
* 
* Converts an unpacked binary string into a printable IP 
* 
* @author Mike Mackintosh - [email protected] 
* @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; 
} 

Beispiele

Mit der dtr_pton Funktion können Sie:

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

Erhalten Sie Ihr Netzwerk und Broadcast:

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

Und Ihre Ausgabe wäre:

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

IPv6 unterstützt keine Broadcast-Funktion, daher gibt es kein Konzept für eine Broadcast-Adresse. –

+0

@ Steve-o Genau, aber da der Begriff Broadcast schon sehr lange in Netzwerken verwendet wird, ist es einfacher für Menschen, wenn sie einen Bereich in IPv6 hervorheben. Dies ist ähnlich dem Subnetzsegment, aber viele Netzwerke erstrecken sich weit über dieses Segment hinaus. –

0

Nun, für die Nachwelt, ich bin Hinzufügen meiner code hier. Und auch als Dankeschön an alle, die mir geholfen haben, das zu notieren, wie ich es für ein ipv6/ip2country Skript brauchte.

Es leicht inspiriert von Code hier gepostet von @mikemacintosh und @Sander Steffann, verbesserte sich leicht (whishful Denken) und gibt ein schönes Objekt Verpackung alle Daten, die Sie/brauchen nicht:

/** 
* This: 
* <code> 
* Ipv6_Prefix2Range('2001:43f8:10::/48'); 
* </code> 
* returns this: 
* <code> 
* 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 
* } 
* </code> 
* 
* 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; 
} 

Ich mag Funktionen und Klassen und nicht mag nicht wieder verwendbaren Code, in den wiederverwendbaren Funktionalität implementiert ist.

PS: Wenn Sie Probleme damit finden, wenden Sie sich bitte an mich zurück. Ich bin weit von einem IPv6-Experten entfernt.