diff options
author | Ermal <eri@pfsense.org> | 2014-02-20 20:00:01 +0000 |
---|---|---|
committer | Ermal <eri@pfsense.org> | 2014-02-20 20:00:01 +0000 |
commit | 03ab9b3028d7650cf50a0d19695d0de28c14a580 (patch) | |
tree | 130a80a68834f06a5eb6f01faa5b159d6f3c46a1 /etc/inc/IPv6.inc | |
parent | 7519cc29aedd0f957b4b124b2b1cf49e16938e2b (diff) | |
download | pfsense-03ab9b3028d7650cf50a0d19695d0de28c14a580.zip pfsense-03ab9b3028d7650cf50a0d19695d0de28c14a580.tar.gz |
Update IPV6.inc to latest 1.2.1 version
Diffstat (limited to 'etc/inc/IPv6.inc')
-rw-r--r-- | etc/inc/IPv6.inc | 515 |
1 files changed, 323 insertions, 192 deletions
diff --git a/etc/inc/IPv6.inc b/etc/inc/IPv6.inc index 7598226..c311b57 100644 --- a/etc/inc/IPv6.inc +++ b/etc/inc/IPv6.inc @@ -1,7 +1,7 @@ <?php /* - pfSense_MODULE: utils + pfSense_MODULE: utils */ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ @@ -22,8 +22,8 @@ * @package Net_IPv6 * @author Alexander Merz <alexander.merz@web.de> * @copyright 2003-2005 The PHP Group - * @license http://www.opensource.org/licenses/bsd-license.php - * @version CVS: $Id: IPv6.inc,v 1.2 2008/11/26 03:54:43 sumacob Exp $ + * @license BSD License http://www.opensource.org/licenses/bsd-license.php + * @version CVS: $Id: IPv6.php 306821 2010-12-29 13:53:22Z alexmerz $ * @link http://pear.php.net/package/Net_IPv6 */ @@ -97,6 +97,24 @@ define("NET_IPV6_LOCAL_LINK", 42); define("NET_IPV6_LOCAL_SITE", 43); /** + * Address Type: Address range to embedded IPv4 ip in an IPv6 address (RFC 4291, Section 2.5.5) + * @see getAddressType() + */ +define("NET_IPV6_IPV4MAPPING", 51); + +/** + * Address Type: Unspecified (RFC 4291, Section 2.5.2) + * @see getAddressType() + */ +define("NET_IPV6_UNSPECIFIED", 52); + +/** + * Address Type: Unspecified (RFC 4291, Section 2.5.3) + * @see getAddressType() + */ +define("NET_IPV6_LOOPBACK", 53); + +/** * Address Type: address can not assigned to a specific type * @see getAddressType() */ @@ -110,51 +128,112 @@ define("NET_IPV6_UNKNOWN_TYPE", 1001); * * @category Net * @package Net_IPv6 - * @copyright 2003-2005 The PHP Group - * @license http://www.opensource.org/licenses/bsd-license.php - * @version $Release$ - * @link http://pear.php.net/package/Net_IPv6 * @author Alexander Merz <alexander.merz@web.de> * @author <elfrink at introweb dot nl> * @author Josh Peck <jmp at joshpeck dot org> + * @copyright 2003-2010 The PHP Group + * @license BSD License http://www.opensource.org/licenses/bsd-license.php + * @version Release: 1.1.0RC5 + * @link http://pear.php.net/package/Net_IPv6 */ -class Net_IPv6 { +class Net_IPv6 +{ - // {{{ removeNetmaskBits() + // {{{ separate() + /** + * Separates an IPv6 address into the address and a prefix length part + * + * @param String $ip the (compressed) IP as Hex representation + * + * @return Array the first element is the IP, the second the prefix length + * @since 1.2.0 + * @access public + * @static + */ + function separate($ip) + { + + $addr = $ip; + $spec = ''; + + if(false === strrpos($ip, '/')) { + + return array($addr, $spec); + + } + + $elements = explode('/', $ip); + + if(2 == count($elements)) { + + $addr = $elements[0]; + $spec = $elements[1]; + + } + + return array($addr, $spec); + + } + // }}} + + // {{{ removeNetmaskSpec() /** - * Removes a possible existing netmask specification at an IP address. + * Removes a possible existing prefix length/ netmask specification at an IP addresse. * - * @param String $ip the (compressed) IP as Hex representation + * @param String $ip the (compressed) IP as Hex representation * * @return String the IP without netmask length * @since 1.1.0 * @access public * @static */ - function removeNetmaskSpec($ip) + function removeNetmaskSpec($ip) { - $addr = $ip; - if (false !== strpos($ip, '/')) { + $elements = Net_IPv6::separate($ip); - $elements = explode('/', $ip); + return $elements[0]; - if (2 == count($elements)) { + } + // }}} + // {{{ removePrefixLength() - $addr = $elements[0]; + /** + * Tests for a prefix length specification in the address + * and removes the prefix length, if exists + * + * The method is technically identical to removeNetmaskSpec() and + * will be dropped in a future release. + * + * @param String $ip a valid ipv6 address + * + * @return String the address without a prefix length + * @access public + * @static + * @see removeNetmaskSpec() + * @deprecated + */ + function removePrefixLength($ip) + { + $pos = strrpos($ip, '/'); - } + if (false !== $pos) { + + return substr($ip, 0, $pos); } - return $addr; + return $ip; } + // }}} + // {{{ getNetmaskSpec() + /** - * Returns a possible existing netmask specification at an IP address. + * Returns a possible existing prefix length/netmask specification on an IP addresse. * - * @param String $ip the (compressed) IP as Hex representation + * @param String $ip the (compressed) IP as Hex representation * * @return String the netmask spec * @since 1.1.0 @@ -163,21 +242,43 @@ class Net_IPv6 { */ function getNetmaskSpec($ip) { - $spec = ''; - if (false !== strpos($ip, '/')) { + $elements = Net_IPv6::separate($ip); - $elements = explode('/', $ip); + return $elements[1]; - if (2 == count($elements)) { + } - $spec = $elements[1]; + // }}} + // {{{ getPrefixLength() - } + /** + * Tests for a prefix length specification in the address + * and returns the prefix length, if exists + * + * The method is technically identical to getNetmaskSpec() and + * will be dropped in a future release. + * + * @param String $ip a valid ipv6 address + * + * @return Mixed the prefix as String or false, if no prefix was found + * @access public + * @static + * @deprecated + */ + function getPrefixLength($ip) + { + if (preg_match("/^([0-9a-fA-F:]{2,39})\/(\d{1,3})*$/", + $ip, $matches)) { + + return $matches[2]; + + } else { + + return false; } - return $spec; } // }}} @@ -186,9 +287,9 @@ class Net_IPv6 { /** * Calculates the network prefix based on the netmask bits. * - * @param String $ip the (compressed) IP in Hex format - * @param int $bits if the number of netmask bits is not part of the IP - * you must provide the number of bits + * @param String $ip the (compressed) IP in Hex format + * @param int $bits if the number of netmask bits is not part of the IP + * you must provide the number of bits * * @return String the network prefix * @since 1.1.0 @@ -232,20 +333,20 @@ class Net_IPv6 { /** * Checks if an (compressed) IP is in a specific address space. * - * IF the IP does not contain the number of netmask bits (F8000::FFFF/16) + * IF the IP does not contains the number of netmask bits (F8000::FFFF/16) * then you have to use the $bits parameter. * - * @param String $ip the IP to check (eg. F800::FFFF) - * @param String $netmask the netmask (eg F800::) - * @param int $bits the number of netmask bits to compare, - * if not given in $ip + * @param String $ip the IP to check (eg. F800::FFFF) + * @param String $netmask the netmask (eg F800::) + * @param int $bits the number of netmask bits to compare, + * if not given in $ip * * @return boolean true if $ip is in the netmask * @since 1.1.0 * @access public * @static */ - function isInNetmask($ip, $netmask, $bits=null) + function isInNetmask($ip, $netmask, $bits=null) { // try to get the bit count @@ -265,7 +366,7 @@ class Net_IPv6 { if (2 == count($elements)) { $netmask = $elements[0]; - $bits = $elements[1]; + $bits = $elements[1]; } @@ -284,9 +385,9 @@ class Net_IPv6 { $binIp = Net_IPv6::_ip2Bin(Net_IPv6::removeNetmaskSpec($ip)); $binNetmask = Net_IPv6::_ip2Bin(Net_IPv6::removeNetmaskSpec($netmask)); - if (null != $bits - && "" != $bits - && 0 == strncmp( $binNetmask, $binIp, $bits)) { + if (null != $bits + && "" != $bits + && 0 == strncmp($binNetmask, $binIp, $bits)) { return true; @@ -301,15 +402,15 @@ class Net_IPv6 { /** * Returns the type of an IPv6 address. * - * RFC 1883, Section 2.3 describes several types of addresses in - * the IPv6 address space. - * Several address types are markers for reserved spaces and as - * a consequence are subject to change. + * RFC 2373, Section 2.3 describes several types of addresses in + * the IPv6 addresse space. + * Several addresse types are markers for reserved spaces and as + * consequence a subject to change. * - * @param String $ip the IP address in Hex format, + * @param String $ip the IP address in Hex format, * compressed IPs are allowed * - * @return int one of the address type constants + * @return int one of the addresse type constants * @access public * @since 1.1.0 * @static @@ -323,6 +424,9 @@ class Net_IPv6 { * @see NET_IPV6_MULTICAST * @see NET_IPV6_LOCAL_LINK * @see NET_IPV6_LOCAL_SITE + * @see NET_IPV6_IPV4MAPPING + * @see NET_IPV6_UNSPECIFIED + * @see NET_IPV6_LOOPBACK * @see NET_IPV6_UNKNOWN_TYPE */ function getAddressType($ip) @@ -330,7 +434,19 @@ class Net_IPv6 { $ip = Net_IPv6::removeNetmaskSpec($ip); $binip = Net_IPv6::_ip2Bin($ip); - if (0 == strncmp('1111111010', $binip, 10)) { + if(0 == strncmp(str_repeat('0', 128), $binip, 128)) { // ::/128 + + return NET_IPV6_UNSPECIFIED; + + } else if(0 == strncmp(str_repeat('0', 127).'1', $binip, 128)) { // ::/128 + + return NET_IPV6_LOOPBACK; + + } else if (0 == strncmp(str_repeat('0', 80).str_repeat('1', 16), $binip, 96)) { // ::ffff/96 + + return NET_IPV6_IPV4MAPPING; + + } else if (0 == strncmp('1111111010', $binip, 10)) { return NET_IPV6_LOCAL_LINK; @@ -346,11 +462,11 @@ class Net_IPv6 { return NET_IPV6_MULTICAST; - } else if (0 == strncmp('00000000', $binip, 8)) { + } else if (0 == strncmp('00000000', $binip, 8)) { return NET_IPV6_RESERVED; - } else if (0 == strncmp('00000001', $binip, 8) + } else if (0 == strncmp('00000001', $binip, 8) || 0 == strncmp('1111110', $binip, 7)) { return NET_IPV6_UNASSIGNED; @@ -380,7 +496,7 @@ class Net_IPv6 { return NET_IPV6_UNICAST_PROVIDER; - } else if (0 == strncmp('100', $binip, 3)) { + } else if (0 == strncmp('100', $binip, 3)) { return NET_IPV6_RESERVED_UNICAST_GEOGRAPHIC; @@ -393,22 +509,28 @@ class Net_IPv6 { // {{{ Uncompress() /** - * Uncompresses an IPv6 address + * Uncompresses an IPv6 adress * - * RFC 2373 allows you to compress zeros in an address to '::'. This - * function expects a valid IPv6 address and expands the '::' to + * RFC 2373 allows you to compress zeros in an adress to '::'. This + * function expects an valid IPv6 adress and expands the '::' to * the required zeros. * * Example: FF01::101 -> FF01:0:0:0:0:0:0:101 * ::1 -> 0:0:0:0:0:0:0:1 * + * @param String $ip a valid IPv6-adress (hex format) + * @param Boolean $leadingZeros if true, leading zeros are added to each + * block of the address + * (FF01::101 -> + * FF01:0000:0000:0000:0000:0000:0000:0101) + * + * @return String the uncompressed IPv6-adress (hex format) * @access public * @see Compress() * @static - * @param string $ip a valid IPv6-address (hex format) - * @return string the uncompressed IPv6-address (hex format) + * @author Pascal Uhlmann */ - function uncompress($ip) + function uncompress($ip, $leadingZeros = false) { $prefix = Net_IPv6::getPrefixLength($ip); @@ -434,7 +556,7 @@ class Net_IPv6 { list($ip1, $ip2) = explode('::', $uip); - if("" == $ip1) { + if ("" == $ip1) { $c1 = -1; @@ -493,12 +615,27 @@ class Net_IPv6 { } else { // xxx::xxx - $fill = str_repeat(':0:', max(1, 6-$c2-$c1)); + $fill = str_repeat(':0:', 6-$c2-$c1); $uip = str_replace('::', $fill, $uip); $uip = str_replace('::', ':', $uip); } } + + if(true == $leadingZeros) { + + $uipT = array(); + $uiparts = explode(':', $uip); + + foreach($uiparts as $p) { + + $uipT[] = sprintf('%04s', $p); + + } + + $uip = implode(':', $uipT); + } + if ('' != $netmask) { $uip = $uip.'/'.$netmask; @@ -512,24 +649,50 @@ class Net_IPv6 { // {{{ Compress() /** - * Compresses an IPv6 address + * Compresses an IPv6 adress * - * RFC 2373 allows you to compress zeros in an address to '::'. This - * function expects a valid IPv6 address and compresses successive zeros + * RFC 2373 allows you to compress zeros in an adress to '::'. This + * function expects an valid IPv6 adress and compresses successive zeros * to '::' * * Example: FF01:0:0:0:0:0:0:101 -> FF01::101 * 0:0:0:0:0:0:0:1 -> ::1 * + * Whe $ip is an already compressed adress the methode returns the value as is, + * also if the adress can be compressed further. + * + * Example: FF01::0:1 -> FF01::0:1 + * + * To enforce maximum compression, you can set the second argument $force to true. + * + * Example: FF01::0:1 -> FF01::1 + * + * @param String $ip a valid IPv6-adress (hex format) + * @param boolean $force if true the adress will be compresses as best as possible (since 1.2.0) + * + * @return tring the compressed IPv6-adress (hex format) * @access public - * @see Uncompress() + * @see Uncompress() * @static - * @param string $ip a valid IPv6-address (hex format) - * @return string the compressed IPv6-address (hex format) * @author elfrink at introweb dot nl */ - function compress($ip) + function compress($ip, $force = false) { + + if(false !== strpos($ip, '::')) { // its already compressed + + if(true == $force) { + + $ip = Net_IPv6::uncompress($ip); + + } else { + + return $ip; + + } + + } + $prefix = Net_IPv6::getPrefixLength($ip); if (false === $prefix) { @@ -546,73 +709,92 @@ class Net_IPv6 { $netmask = Net_IPv6::getNetmaskSpec($ip); $ip = Net_IPv6::removeNetmaskSpec($ip); - if (!strstr($ip, '::')) { - - $ipp = explode(':',$ip); + $ipp = explode(':', $ip); - for ($i = 0; $i < count($ipp); $i++) { + for ($i = 0; $i < count($ipp); $i++) { - $ipp[$i] = dechex(hexdec($ipp[$i])); + $ipp[$i] = dechex(hexdec($ipp[$i])); - } + } - $cip = ':' . join(':',$ipp) . ':'; + $cip = ':' . join(':', $ipp) . ':'; - preg_match_all("/(:0)+/", $cip, $zeros); + preg_match_all("/(:0)+/", $cip, $zeros); - if (count($zeros[0]) > 0) { + if (count($zeros[0]) > 0) { - $match = ''; + $match = ''; - foreach($zeros[0] as $zero) { + foreach ($zeros[0] as $zero) { - if (strlen($zero) > strlen($match)) { + if (strlen($zero) > strlen($match)) { - $match = $zero; + $match = $zero; - } } + } - $cip = preg_replace('/' . $match . '/', ':', $cip, 1); + $cip = preg_replace('/' . $match . '/', ':', $cip, 1); - } + } - $cip = preg_replace('/((^:)|(:$))/', '' ,$cip); - $cip = preg_replace('/((^:)|(:$))/', '::' ,$cip); + $cip = preg_replace('/((^:)|(:$))/', '', $cip); + $cip = preg_replace('/((^:)|(:$))/', '::', $cip); - } else { - // The input IP appears to be compressed already, give it back as-is to the caller. - $cip = $ip; - } - if ('' != $netmask) { + if ('' != $netmask) { - $cip = $cip.'/'.$netmask; + $cip = $cip.'/'.$netmask; - } + } + + return $cip.$prefix; - return $cip.$prefix; } // }}} + // {{{ isCompressible() + + /** + * Checks, if an IPv6 adress can be compressed + * + * @param String $ip a valid IPv6 adress + * + * @return Boolean true, if adress can be compressed + * + * @access public + * @since 1.2.0b + * @static + * @author Manuel Schmitt + */ + function isCompressible($ip) + { + + return (bool)($ip != Net_IPv6::compress($address)); + + } + + // }}} // {{{ SplitV64() /** - * Splits an IPv6 address into the IPv6 and a possible IPv4 part + * Splits an IPv6 adress into the IPv6 and a possible IPv4 part * - * RFC 2373 allows you to note the last two parts of an IPv6 address as - * an IPv4 compatible address + * RFC 2373 allows you to note the last two parts of an IPv6 adress as + * an IPv4 compatible adress * * Example: 0:0:0:0:0:0:13.1.68.3 * 0:0:0:0:0:FFFF:129.144.52.38 * - * @param string $ip a valid IPv6-address (hex format) + * @param String $ip a valid IPv6-adress (hex format) + * @param Boolean $uncompress if true, the address will be uncompressed + * before processing * - * @return array [0] contains the IPv6 part, + * @return Array [0] contains the IPv6 part, * [1] the IPv4 part (hex format) * @access public * @static */ - function SplitV64($ip, $uncompress = true) + function SplitV64($ip, $uncompress = true) { $ip = Net_IPv6::removeNetmaskSpec($ip); @@ -641,16 +823,17 @@ class Net_IPv6 { // {{{ checkIPv6() /** - * Checks an IPv6 address + * Checks an IPv6 adress * * Checks if the given IP is IPv6-compatible * + * @param String $ip a valid IPv6-adress + * + * @return Boolean true if $ip is an IPv6 adress * @access public * @static - * @param string $ip a valid IPv6-address - * @return boolean true if $ip is an IPv6 address */ - function checkIPv6($ip) + function checkIPv6($ip) { $ip = Net_IPv6::removePrefixLength($ip); $ip = Net_IPv6::removeNetmaskSpec($ip); @@ -658,12 +841,17 @@ class Net_IPv6 { $ipPart = Net_IPv6::SplitV64($ip); $count = 0; - if (!empty($ipPart[0])) - { + if (!empty($ipPart[0])) { $ipv6 =explode(':', $ipPart[0]); for ($i = 0; $i < count($ipv6); $i++) { + if(4 < strlen($ipv6[$i])) { + + return false; + + } + $dec = hexdec($ipv6[$i]); $hex = strtoupper(preg_replace("/^[0]{1,3}(.*[0-9a-fA-F])$/", "\\1", @@ -684,7 +872,7 @@ class Net_IPv6 { } else if (6 == $count and !empty($ipPart[1])) { - $ipv4 = explode('.',$ipPart[1]); + $ipv4 = explode('.', $ipPart[1]); $count = 0; for ($i = 0; $i < count($ipv4); $i++) { @@ -719,60 +907,6 @@ class Net_IPv6 { } // }}} - // {{{ getPrefixLength() - - /** - * Tests for a prefix length specification in the address - * and returns the prefix length, if exists - * - * @param String $ip a valid ipv6 address - * - * @return Mixed the prefix as String or false, if no prefix was found - * @access public - * @static - */ - function getPrefixLength($ip) - { - if (preg_match("/^([0-9a-fA-F:]{2,39})\/(\d{1,3})*$/", - $ip, $matches)) { - - return $matches[2]; - - } else { - - return false; - - } - - } - - // }}} - // {{{ removePrefixLength() - - /** - * Tests for a prefix length specification in the address - * and removes the prefix length, if exists - * - * @param String $ip a valid ipv6 address - * - * @return String the address without a prefix length - * @access public - * @static - */ - function removePrefixLength($ip) - { - $pos = strrpos($ip, '/'); - - if (false !== $pos) { - - return substr($ip, 0, $pos); - - } - - return $ip; - } - - // }}} // {{{ _parseAddress() @@ -781,14 +915,14 @@ class Net_IPv6 { * for a given IP and netmask specification * * The netmask may be a part of the $ip or - * the number of netmask bits is provided via $bits + * the number of netwask bits is provided via $bits * * The result is an indexed array. The key 'start' - * contains the lowest possible IP address. The key + * contains the lowest possible IP adress. The key * 'end' the highest address. * - * @param String $ip the IPv6 address - * @param String $bits the optional count of netmask bits + * @param String $ipToParse the IPv6 address + * @param String $bits the optional count of netmask bits * * @return Array ['start', 'end'] the lowest and highest IPv6 address * @access public @@ -802,43 +936,40 @@ class Net_IPv6 { $ip = null; $bitmask = null; - if( null == $bits ) - { + if ( null == $bits ) { - $elements = explode('/', $ipToParse); + $elements = explode('/', $ipToParse); - if( 2 == count($elements) ) { + if ( 2 == count($elements) ) { - $ip = Net_IPv6::uncompress($elements[0]); - $bitmask = $elements[1]; + $ip = Net_IPv6::uncompress($elements[0]); + $bitmask = $elements[1]; - } else { + } else { - include_once 'PEAR.inc'; + include_once 'PEAR.php'; - return PEAR::raiseError(NET_IPV6_NO_NETMASK_MSG, + return PEAR::raiseError(NET_IPV6_NO_NETMASK_MSG, NET_IPV6_NO_NETMASK); - } - } - else - { + } + } else { - $ip = Net_IPv6::uncompress($ipToParse); - $bitmask = $bits; + $ip = Net_IPv6::uncompress($ipToParse); + $bitmask = $bits; - } + } - $binNetmask = str_repeat('1', $bitmask). + $binNetmask = str_repeat('1', $bitmask). str_repeat('0', 128 - $bitmask); - $maxNetmask = str_repeat('1', 128); - $netmask = Net_IPv6::_bin2Ip($binNetmask); + $maxNetmask = str_repeat('1', 128); + $netmask = Net_IPv6::_bin2Ip($binNetmask); - $startAddress = Net_IPv6::_bin2Ip(Net_IPv6::_ip2Bin($ip) - & $binNetmask); - $endAddress = Net_IPv6::_bin2Ip(Net_IPv6::_ip2Bin($ip) - | ($binNetmask ^ $maxNetmask)); + $startAddress = Net_IPv6::_bin2Ip(Net_IPv6::_ip2Bin($ip) + & $binNetmask); + $endAddress = Net_IPv6::_bin2Ip(Net_IPv6::_ip2Bin($ip) + | ($binNetmask ^ $maxNetmask)); - return array('start' => $startAddress, 'end' => $endAddress); + return array('start' => $startAddress, 'end' => $endAddress); } // }}} @@ -864,7 +995,7 @@ class Net_IPv6 { $parts = explode(':', $ip); - foreach($parts as $v) { + foreach ( $parts as $v ) { $str = base_convert($v, 16, 2); $binstr .= str_pad($str, 16, '0', STR_PAD_LEFT); @@ -880,7 +1011,7 @@ class Net_IPv6 { /** * Converts an IPv6 address from Binary into Hex representation. * - * @param String $ip the IP as binary + * @param String $bin the IP address as binary * * @return String the uncompressed Hex representation * @access private @@ -892,20 +1023,20 @@ class Net_IPv6 { if (strlen($bin) < 128) { - $bin = str_pad($str, 128, '0', STR_PAD_LEFT); + $bin = str_pad($bin, 128, '0', STR_PAD_LEFT); } $parts = str_split($bin, "16"); - foreach($parts as $v) { + foreach ( $parts as $v ) { $str = base_convert($v, 2, 16); $ip .= $str.":"; } - $ip = substr($ip, 0,-1); + $ip = substr($ip, 0, -1); return $ip; } |