I am able to do this with IPv4 using code snippets from various online sources. I was wondering if there was a way to do it with IPv6.
Basically I just need a form that I can enter an IPv6 address and prefix (ex: f080:42d2:581a::0/68) and it calculates the network address, first useable address, last useable address, and broadcast address. Then just prints to screen. Not looking to store it in a database or anything yet.
Medium customers get a /56 prefix. That gives them 256 /64 subnets.
IPv6 networks are written using CIDR notation and use the same CIDR technology as is employed by CIDR on IPv4. Under CIDR, IPv6 unicast addresses can be aggregated with prefixes of arbitrary bit length, similar to IPv4 addresses.
10.255. The prefix-length in IPv6 is the equivalent of the subnet mask in IPv4. However, rather than being expressed in four octets like it is in IPv4, it is expressed as an integer between 1 through 128.
First of all: IPv6 doesn't have network and broadcast addresses. You can use all addresses in a prefix. Second: On a LAN the prefix length is always (well, 99.x% of the time) a /64. Routing a /68 would break IPv6 features like stateless auto configuration.
Below is a verbose implementation of an IPv6 prefix calculator:
<?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";
?>
It should output:
Prefix: 2001:db8:abc:1400::/54
First: 2001:db8:abc:1400::
Last: 2001:db8:abc:17ff:ffff:ffff:ffff:ffff
For those who stumble upon this question, you can do this more effectively using the dtr_pton
and dtr_ntop
functions and dTRIP
class found on GitHub.
We also have noticed a lack of focus and tools with IPv6 in PHP, and put together this article, http://www.highonphp.com/5-tips-for-working-with-ipv6-in-php, which may be of help to others.
Function Source
This converts and IP to a binary representation:
/**
* 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;
}
This converts a binary representation to printable 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;
}
Examples
Using the dtr_pton
function you can:
$ip = dtr_pton("fe80:1:2:3:a:bad:1dea:dad");
$mask = dtr_pton("ffff:ffff:ffff:ffff:ffff:fff0::");
Get your Network and Broadcast:
var_dump( dtr_ntop( $ip & $mask ) );
var_dump( dtr_ntop( $ip | ~ $mask ) );
And your output would be:
string(18) "fe80:1:2:3:a:ba0::"
string(26) "fe80:1:2:3:a:baf:ffff:ffff"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With