package.xml 0000644 0000765 0000024 00000030574 13320646475 013742 0 ustar alexandermerz staff
Net_IPv6
pear.php.net
Check and validate IPv6 addresses
The class allows you to:
* check if an address is an IPv6 address
* compress/uncompress IPv6 addresses
* check for an IPv4 compatible ending in an IPv6 address
* check the assigned address space of an IPv6 address
* do netmask calculations
Alexander Merz
alexmerz
alexander.merz@web.de
yes
2018-07-09
1.3.0b4
1.2.2
beta
stable
BSD
fix #23755 _ip2Bin() incorrectly convert IPv4 mapped into binary
fix #23756 Compressed netmasks incorrectly detected in isInNetmask()
5.0.0
1.4.0b1
2017-07-27
1.3.0b3
1.2.2
beta
stable
BSD
fix #13006 failed compressing ipv6 with ip4 part
fix #21140 splitV64 for double-colon do not uncompress case
2016-05-25
1.3.0b2
1.2.2
beta
stable
BSD
#21046 checkIPv6 wrongly validates IPv6 IPs with leading and/or trailing :
2015-06-14
1.3.0b1
1.2.2
beta
stable
BSD
#20558 String offset cast occurred
Use static keyword for class method declarations
Use public/protected keyword class method declarations
2012-03-23
1.2.2b2
1.2.2
beta
alpha
BSD
#19334 CheckIPv6 accepted invalid characters
2011-11-15
1.2.2b
1.2.2
beta
alpha
BSD
#18687 Add recommendedFormat() provided by Tetsuji Koyama to respect RFC5952 about shortening of 0-Byte
segments.
The method may become a part of compress() in a stable release.
#18976 Rok Potocnik spotted a missing range check for the netmask value while checking an IPv6 address.
2011-02-07
1.2.1
1.2.0
stable
stable
BSD
No Changes. Go to stable.
2010-12-30
1.2.1RC1
1.2.0
beta
beta
BSD
Go to Release Candidate.
Updated Peardoc to reflect the API changes.
2010-12-22
1.2.1b1
1.2.0
beta
alpha
BSD
Feature request:
+ add parameter to uncompress() to add leading zeros to an address (Pascal Uhlmann)
2010-11-25
1.2.1b
1.2.0
beta
alpha
BSD
#18085 Fix wrong file path
2010-11-18
1.2.0b
1.2.0
beta
alpha
BSD
+ New method isCompressible()
+ New method separate()
+ compress() got a second parameter to enforce compression
+ add new address types
- deprecated getPrefixLength() (technical identical to getNetmaskSpec)
- deprecated removePrefixLength() (technical identical to removeNetmaskSpec)
2010-11-08
1.1.0
1.1.0
stable
stable
BSD
Jump from beta to stable.
Fixed:
#17819 documentation needs to be updated
1.1.0b2
1.1.0b1
beta
beta
BSD
Fixed:
#14747 Compressing an already compressed IP returns the IP "as is" now
#15947 checkIPv6 returned true although the IP was too long
#16220 using the wrong variable in _bin2Ip
1.1.0b1
1.1.0b1
beta
beta
BSD
Because this release adds a new method and some bug tickets are still open, the package
release is named as Beta, instead of releasing a 5th RC version.
#14728 add parseAddress(), thanks to Nicholas Williams!
#14767 most CS issues should be solved
1.1.0RC3
1.1.0RC3
beta
beta
BSD
Fix Bug #12442, thanks to pear at erikdebruijn dot nl
+ add getNetmaskSpec()
1.1.0RC4
1.1.0RC4
beta
beta
BSD
take care of prefix length specification in an address, thanks to Jens Ott
1.0
1.0
stable
stable
2004-03-02
BSD
First official release
1.0.1
1.0.1
stable
stable
2004-11-24
BSD
rewrite compress()/uncompress
fixes this bugs:
Bug #2803 compress() adds colon
Bug #2802 compress() doesn't compress correctly
Thanks to cmoehrke at netviser dot de
1.0.2
1.0.2
stable
stable
2005-02-13
BSD
Bug #3404: checkIPv6() is case sensitive
Bug #3405: compress() does not compress '0000'
Thanks to elfrink at introweb dot nl
1.0.3
1.0.3
stable
stable
2005-03-19
BSD
Bug #3851: IPv4-mapped/compatible IPv6 uncompress bug
Thanks to dtaylor at jasi dot com
1.0.4
1.0.4
stable
stable
2005-08-03
BSD
Bug #4977: trying to compress where nothing is to compress
Thanks to pvenegas at gmail dot com
1.0.5
1.0.5
stable
stable
2005-09-01
BSD
Bug #3405 again: problem with compressing
Thanks to elfrink at introweb dot nl
1.1.0RC1
1.1.0RC1
beta
beta
2005-11-24
BSD
This new minor version adds some methods proposed
by Josh Peck (jmp @ joshpeck dot org).
+ Change license to BSD
+ Improved comments and docblocks
+ add removeNetmaskSpec()
+ add getNetmask()
+ add isInNetmask()
+ add getAddressType()
+ add _ip2Bin()
+ add _bin2Ip()
+ add serveral constants for address types
1.1.0RC2
1.1.0RC2
beta
beta
2006-02-09
BSD
- fixed a notice, when removeNetmaskSpec is used on an IP
without a netmask
1.1.0b2
1.1.0b1
beta
beta
2010-02-12
BSD
Fixed:
#14747 Compressing an already compressed IP returns the IP "as is" now
#15947 checkIPv6 returned true although the IP was too long
#16220 using the wrong variable in _bin2Ip
Net_IPv6-1.3.0b4/Net/IPv6.php 0000644 0000765 0000024 00000066337 13320646475 016133 0 ustar alexandermerz staff
* @copyright 2003-2005 The PHP Group
* @license BSD License http://www.opensource.org/licenses/bsd-license.php
* @version CVS: $Id: IPv6.php 340792 2016-10-29 14:56:52Z alexmerz $
* @link http://pear.php.net/package/Net_IPv6
*/
// {{{ constants
/**
* Error message if netmask bits was not found
* @see isInNetmask
*/
define("NET_IPV6_NO_NETMASK_MSG", "Netmask length not found");
/**
* Error code if netmask bits was not found
* @see isInNetmask
*/
define("NET_IPV6_NO_NETMASK", 10);
/**
* Address Type: Unassigned (RFC 1884, Section 2.3)
* @see getAddressType()
*/
define("NET_IPV6_UNASSIGNED", 1);
/**
* Address Type: Reserved (RFC 1884, Section 2.3)
* @see getAddressType()
*/
define("NET_IPV6_RESERVED", 11);
/**
* Address Type: Reserved for NSAP Allocation (RFC 1884, Section 2.3)
* @see getAddressType()
*/
define("NET_IPV6_RESERVED_NSAP", 12);
/**
* Address Type: Reserved for IPX Allocation (RFC 1884, Section 2.3)
* @see getAddressType()
*/
define("NET_IPV6_RESERVED_IPX", 13);
/**
* Address Type: Reserved for Geographic-Based Unicast Addresses
* (RFC 1884, Section 2.3)
* @see getAddressType()
*/
define("NET_IPV6_RESERVED_UNICAST_GEOGRAPHIC", 14);
/**
* Address Type: Provider-Based Unicast Address (RFC 1884, Section 2.3)
* @see getAddressType()
*/
define("NET_IPV6_UNICAST_PROVIDER", 22);
/**
* Address Type: Multicast Addresses (RFC 1884, Section 2.3)
* @see getAddressType()
*/
define("NET_IPV6_MULTICAST", 31);
/**
* Address Type: Link Local Use Addresses (RFC 1884, Section 2.3)
* @see getAddressType()
*/
define("NET_IPV6_LOCAL_LINK", 42);
/**
* Address Type: Link Local Use Addresses (RFC 1884, Section 2.3)
* @see getAddressType()
*/
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()
*/
define("NET_IPV6_UNKNOWN_TYPE", 1001);
// }}}
// {{{ Net_IPv6
/**
* Class to validate and to work with IPv6 addresses.
*
* @category Net
* @package Net_IPv6
* @author Alexander Merz
* @author
* @author Josh Peck
* @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
{
// {{{ 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
*/
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 prefix length/ netmask specification at an IP address.
*
* @param String $ip the (compressed) IP as Hex representation
*
* @return String the IP without netmask length
* @since 1.1.0
* @access public
* @static
*/
public static function removeNetmaskSpec($ip)
{
$elements = Net_IPv6::separate($ip);
return $elements[0];
}
// }}}
// {{{ removePrefixLength()
/**
* 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
*/
public static function removePrefixLength($ip)
{
$pos = strrpos($ip, '/');
if (false !== $pos) {
return substr($ip, 0, $pos);
}
return $ip;
}
// }}}
// {{{ getNetmaskSpec()
/**
* Returns a possible existing prefix length/netmask specification on an IP address.
*
* @param String $ip the (compressed) IP as Hex representation
*
* @return String the netmask spec
* @since 1.1.0
* @access public
* @static
*/
public static function getNetmaskSpec($ip)
{
$elements = Net_IPv6::separate($ip);
return $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
*/
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;
}
}
// }}}
// {{{ getNetmask()
/**
* 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
*
* @return String the network prefix
* @since 1.1.0
* @access public
* @static
*/
public static function getNetmask($ip, $bits = null)
{
if (null==$bits) {
$elements = explode('/', $ip);
if (2 == count($elements)) {
$addr = $elements[0];
$bits = $elements[1];
} else {
include_once 'PEAR.php';
return PEAR::raiseError(NET_IPV6_NO_NETMASK_MSG,
NET_IPV6_NO_NETMASK);
}
} else {
$addr = $ip;
}
$addr = Net_IPv6::uncompress($addr);
$binNetmask = str_repeat('1', $bits).str_repeat('0', 128 - $bits);
return Net_IPv6::_bin2Ip(Net_IPv6::_ip2Bin($addr) & $binNetmask);
}
// }}}
// {{{ isInNetmask()
/**
* 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)
* 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
*
* @return boolean true if $ip is in the netmask
* @since 1.1.0
* @access public
* @static
*/
public static function isInNetmask($ip, $netmask, $bits=null)
{
// try to get the bit count
if (null == $bits) {
$elements = explode('/', $ip);
if (2 == count($elements)) {
$ip = $elements[0];
$bits = $elements[1];
} else if (null == $bits) {
$elements = explode('/', $netmask);
if (2 == count($elements)) {
$netmask = $elements[0];
$bits = $elements[1];
// Correctly uncompress netmasks with prefixes, ie ::FFFF/96 == 0:0:0:0:0:FFFF:0:0/96
// Need only for xxx::yyy/zz and ::yyy/zz
if (preg_match('/^(\:\:[a-f\d]{1,4}|[a-f\d]{1,4}.*\:\:.*[a-f\d]{1,4})$/', $netmask) &&
!preg_match('/\:0+$/', $netmask)) {
$c_bits = intval((128 - $bits) / 16);
$netmask .= str_repeat(':0', $c_bits);
}
}
if (null == $bits) {
include_once 'PEAR.php';
return PEAR::raiseError(NET_IPV6_NO_NETMASK_MSG,
NET_IPV6_NO_NETMASK);
}
}
}
$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)) {
return true;
}
return false;
}
// }}}
// {{{ getAddressType()
/**
* Returns the type of an IPv6 address.
*
* RFC 2373, 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.
*
* @param String $ip the IP address in Hex format,
* compressed IPs are allowed
*
* @return int one of the address type constants
* @access public
* @since 1.1.0
* @static
*
* @see NET_IPV6_UNASSIGNED
* @see NET_IPV6_RESERVED
* @see NET_IPV6_RESERVED_NSAP
* @see NET_IPV6_RESERVED_IPX
* @see NET_IPV6_RESERVED_UNICAST_GEOGRAPHIC
* @see NET_IPV6_UNICAST_PROVIDER
* @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
*/
public static function getAddressType($ip)
{
$ip = Net_IPv6::removeNetmaskSpec($ip);
$binip = Net_IPv6::_ip2Bin($ip);
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;
} else if (0 == strncmp('1111111011', $binip, 10)) {
return NET_IPV6_LOCAL_SITE;
} else if (0 == strncmp('111111100', $binip, 9)) {
return NET_IPV6_UNASSIGNED;
} else if (0 == strncmp('11111111', $binip, 8)) {
return NET_IPV6_MULTICAST;
} else if (0 == strncmp('00000000', $binip, 8)) {
return NET_IPV6_RESERVED;
} else if (0 == strncmp('00000001', $binip, 8)
|| 0 == strncmp('1111110', $binip, 7)) {
return NET_IPV6_UNASSIGNED;
} else if (0 == strncmp('0000001', $binip, 7)) {
return NET_IPV6_RESERVED_NSAP;
} else if (0 == strncmp('0000010', $binip, 7)) {
return NET_IPV6_RESERVED_IPX;
} else if (0 == strncmp('0000011', $binip, 7) ||
0 == strncmp('111110', $binip, 6) ||
0 == strncmp('11110', $binip, 5) ||
0 == strncmp('00001', $binip, 5) ||
0 == strncmp('1110', $binip, 4) ||
0 == strncmp('0001', $binip, 4) ||
0 == strncmp('001', $binip, 3) ||
0 == strncmp('011', $binip, 3) ||
0 == strncmp('101', $binip, 3) ||
0 == strncmp('110', $binip, 3)) {
return NET_IPV6_UNASSIGNED;
} else if (0 == strncmp('010', $binip, 3)) {
return NET_IPV6_UNICAST_PROVIDER;
} else if (0 == strncmp('100', $binip, 3)) {
return NET_IPV6_RESERVED_UNICAST_GEOGRAPHIC;
}
return NET_IPV6_UNKNOWN_TYPE;
}
// }}}
// {{{ Uncompress()
/**
* Uncompresses an IPv6 address
*
* RFC 2373 allows you to compress zeros in an address to '::'. This
* function expects a valid IPv6 address 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-address (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-address (hex format)
* @access public
* @see Compress()
* @static
* @author Pascal Uhlmann
*/
public static function uncompress($ip, $leadingZeros = false)
{
$prefix = Net_IPv6::getPrefixLength($ip);
if (false === $prefix) {
$prefix = '';
} else {
$ip = Net_IPv6::removeNetmaskSpec($ip);
$prefix = '/'.$prefix;
}
$netmask = Net_IPv6::getNetmaskSpec($ip);
$uip = Net_IPv6::removeNetmaskSpec($ip);
$c1 = -1;
$c2 = -1;
if (false !== strpos($uip, '::') ) {
list($ip1, $ip2) = explode('::', $uip, 2);
if ("" == $ip1) {
$c1 = -1;
} else {
$pos = 0;
if (0 < ($pos = substr_count($ip1, ':'))) {
$c1 = $pos;
} else {
$c1 = 0;
}
}
if ("" == $ip2) {
$c2 = -1;
} else {
$pos = 0;
if (0 < ($pos = substr_count($ip2, ':'))) {
$c2 = $pos;
} else {
$c2 = 0;
}
}
if (strstr($ip2, '.')) {
$c2++;
}
if (-1 == $c1 && -1 == $c2) { // ::
$uip = "0:0:0:0:0:0:0:0";
} else if (-1 == $c1) { // ::xxx
$fill = str_repeat('0:', max(1, 7-$c2));
$uip = str_replace('::', $fill, $uip);
} else if (-1 == $c2) { // xxx::
$fill = str_repeat(':0', max(1, 7-$c1));
$uip = str_replace('::', $fill, $uip);
} else { // xxx::xxx
$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;
}
return $uip.$prefix;
}
// }}}
// {{{ Compress()
/**
* Compresses an IPv6 address
*
* RFC 2373 allows you to compress zeros in an address to '::'. This
* function expects a valid IPv6 address 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
*
* When $ip is an already compressed address and $force is false, the method returns
* the value as is, even if the address 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-address (hex format)
* @param boolean $force if true the address will be compressed as best as possible (since 1.2.0)
*
* @return String the compressed IPv6-address (hex format)
* @access public
* @see Uncompress()
* @static
* @author elfrink at introweb dot nl
*/
public static 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) {
$prefix = '';
} else {
$ip = Net_IPv6::removeNetmaskSpec($ip);
$prefix = '/'.$prefix;
}
$split = Net_IPv6::splitV64($ip);
$ip = $split[0];
$netmask = Net_IPv6::getNetmaskSpec($ip);
$ip = Net_IPv6::removeNetmaskSpec($ip);
$ipp = explode(':', $ip);
for ($i = 0; $i < count($ipp); $i++) {
$ipp[$i] = dechex(hexdec($ipp[$i]));
}
$cip = ':' . join(':', $ipp) . ':';
preg_match_all("/(:0)(:0)+/", $cip, $zeros);
if (count($zeros[0]) > 0) {
$match = '';
foreach ($zeros[0] as $zero) {
if (strlen($zero) > strlen($match)) {
$match = $zero;
}
}
$cip = preg_replace('/' . $match . '/', ':', $cip, 1);
}
if ($cip != "::") {
$cip = preg_replace('/((^:)|(:$))/', '', $cip);
$cip = preg_replace('/((^:)|(:$))/', '::', $cip);
}
if ('' != $split[1]) { // add ipv4 part is available
$cip = $cip.$split[1];
}
if ('' != $netmask) {
$cip = $cip.'/'.$netmask;
}
return $cip.$prefix;
}
// }}}
// {{{ recommendedFormat()
/**
* Represent IPv6 address in RFC5952 format.
*
* @param String $ip a valid IPv6-address (hex format)
*
* @return String the recommended representation of IPv6-address (hex format)
* @access public
* @see compress()
* @static
* @author koyama at hoge dot org
* @todo This method may become a part of compress() in a further releases
*/
public static function recommendedFormat($ip)
{
$compressed = self::compress($ip, true);
// RFC5952 4.2.2
// The symbol "::" MUST NOT be used to shorten just one
// 16-bit 0 field.
if ((substr_count($compressed, ':') == 7) &&
(strpos($compressed, '::') !== false)) {
$compressed = str_replace('::', ':0:', $compressed);
}
return $compressed;
}
// }}}
// {{{ isCompressible()
/**
* Checks, if an IPv6 address can be compressed
*
* @param String $ip a valid IPv6 address
*
* @return Boolean true, if address can be compressed
* @access public
* @since 1.2.0b
* @static
* @author Manuel Schmitt
*/
public static function isCompressible($ip)
{
return (bool)($ip != Net_IPv6::compress($address));
}
// }}}
// {{{ SplitV64()
/**
* Splits an IPv6 address 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
*
* 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 Boolean $uncompress if true, the address will be uncompressed
* before processing
*
* @return Array [0] contains the IPv6 part,
* [1] the IPv4 part (hex format)
* @access public
* @static
*
* @author Alexander Merz
.... * @author phildavis
*/
public static function SplitV64($ip, $uncompress = true)
{
$ip = Net_IPv6::removeNetmaskSpec($ip);
if ($uncompress) {
$ip = Net_IPv6::Uncompress($ip);
}
if (strstr($ip, '.')) {
$pos = strrpos($ip, ':');
if(false === $pos) {
return array("", $ip);
}
$ip{$pos} = '_';
$ipPart = explode('_', $ip);
if ($ip{$pos-1} === ":") {
$ipPart[0] .= ":";
}
return $ipPart;
} else {
return array($ip, "");
}
}
// }}}
// {{{ checkIPv6()
/**
* Checks an IPv6 address
*
* Checks if the given IP is IPv6-compatible
*
* @param String $ip a valid IPv6-address
*
* @return Boolean true if $ip is an IPv6 address
* @access public
* @static
*/
public static function checkIPv6($ip)
{
$elements = Net_IPv6::separate($ip);
$ip = $elements[0];
if('' != $elements[1] && ( !is_numeric($elements[1]) || 0 > $elements || 128 < $elements[1])) {
return false;
}
$ipPart = Net_IPv6::SplitV64($ip);
$count = 0;
if (!empty($ipPart[0])) {
$ipv6 = explode(':', $ipPart[0]);
if(8 < count($ipv6)) {
return false;
}
foreach($ipv6 as $element) { // made a validate precheck
if(!preg_match('/[0-9a-fA-F]*/', $element)) {
return false;
}
}
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",
$ipv6[$i]));
if ($ipv6[$i] >= 0 && $dec <= 65535
&& $hex == strtoupper(dechex($dec))) {
$count++;
}
}
if (8 == $count and empty($ipPart[1])) {
return true;
} else if (6 == $count and !empty($ipPart[1])) {
$ipv4 = explode('.', $ipPart[1]);
$count = 0;
for ($i = 0; $i < count($ipv4); $i++) {
if ($ipv4[$i] >= 0 && (integer)$ipv4[$i] <= 255
&& preg_match("/^\d{1,3}$/", $ipv4[$i])) {
$count++;
}
}
if (4 == $count) {
return true;
}
} else {
return false;
}
} else {
return false;
}
}
// }}}
// {{{ _parseAddress()
/**
* Returns the lowest and highest IPv6 address
* 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 result is an indexed array. The key 'start'
* contains the lowest possible IP address. The key
* 'end' the highest address.
*
* @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
* @static
* @author Nicholas Williams
*/
public static function parseAddress($ipToParse, $bits = null)
{
$ip = null;
$bitmask = null;
if ( null == $bits ) {
$elements = explode('/', $ipToParse);
if ( 2 == count($elements) ) {
$ip = Net_IPv6::uncompress($elements[0]);
$bitmask = $elements[1];
} else {
include_once 'PEAR.php';
return PEAR::raiseError(NET_IPV6_NO_NETMASK_MSG,
NET_IPV6_NO_NETMASK);
}
} else {
$ip = Net_IPv6::uncompress($ipToParse);
$bitmask = $bits;
}
$binNetmask = str_repeat('1', $bitmask).
str_repeat('0', 128 - $bitmask);
$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));
return array('start' => $startAddress, 'end' => $endAddress);
}
// }}}
// {{{ _ip2Bin()
/**
* Converts an IPv6 address from Hex into Binary representation.
*
* @param String $ip the IP to convert (a:b:c:d:e:f:g:h),
* compressed IPs are allowed
*
* @return String the binary representation
* @access private
* @since 1.1.0
*/
protected static function _ip2Bin($ip)
{
$binstr = '';
$ip = Net_IPv6::removeNetmaskSpec($ip);
// Correctly convert IPv4 mapped addresses (::ffff:x.x.x.x)
list(, $ipv4) = Net_IPv6::SplitV64($ip, FALSE);
if (strlen($ipv4)) {
$ipv4map = explode('.', $ipv4, 4);
$ipv4replace = dechex($ipv4map[0] * 256 + $ipv4map[1]) . ':' . dechex($ipv4map[2] * 256 + $ipv4map[3]);
$ip = str_replace($ipv4, $ipv4replace, $ip);
}
$ip = Net_IPv6::uncompress($ip);
$parts = explode(':', $ip);
foreach ( $parts as $v ) {
$str = base_convert($v, 16, 2);
$binstr .= str_pad($str, 16, '0', STR_PAD_LEFT);
}
return $binstr;
}
// }}}
// {{{ _bin2Ip()
/**
* Converts an IPv6 address from Binary into Hex representation.
*
* @param String $bin the IP address as binary
*
* @return String the uncompressed Hex representation
* @access private
* @since 1.1.0
*/
protected static function _bin2Ip($bin)
{
$ip = "";
if (strlen($bin) < 128) {
$bin = str_pad($bin, 128, '0', STR_PAD_LEFT);
}
$parts = str_split($bin, "16");
foreach ( $parts as $v ) {
$str = base_convert($v, 2, 16);
$ip .= $str.":";
}
$ip = substr($ip, 0, -1);
return $ip;
}
// }}}
}
// }}}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* c-hanging-comment-ender-p: nil
* End:
*/
?>
Net_IPv6-1.3.0b4/tests/AllTests.php 0000755 0000765 0000024 00000051017 13320646475 017506 0 ustar alexandermerz staff |
// +----------------------------------------------------------------------+
//
// $Id: AllTests.php 340792 2016-10-29 14:56:52Z alexmerz $
require_once "Net/IPv6.php";
/**
* This testcases tests for several bugs and general topics
*
* @author Alexander Merz
* @package Net_IPv6
* @version $Id: AllTests.php 340792 2016-10-29 14:56:52Z alexmerz $
* @access public
*/
class NetIPv6Test extends PHPUnit_Framework_TestCase {
protected $ip;
protected static function getMethod($name) {
$class = new ReflectionClass('Net_IPv6');
$method = $class->getMethod($name);
$method->setAccessible(true);
return $method;
}
public function setUp() {
$this->ip = new Net_IPv6();
}
/**
* tests if checkIPv6 can handle prefix length
*/
public function testCheckIPv6WithPrefix() {
$testip = "FE80:FFFF:0:FFFF:129:144:52:38/60";
$is = $this->ip->checkIPv6($testip);
$this->assertTrue($is);
}
/**
* tests isInNetmask() with no netmask length given
*/
public function testIsInNetmaskNoNetmask() {
$testip = "FE80:FFFF:0:FFFF:129:144:52:38";
$testprefix = "EE80::";
$is = $this->ip->isInNetmask($testip, $testprefix);
$this->assertTrue(PEAR::isError($is));
}
/**
* tests isInNetmask() with the netmask length in
* the third parameter
*/
public function testIsInNetmaskWithBitsAsParameter() {
$testip = "FE80:FFFF:0:FFFF:129:144:52:38";
$testprefix = "FE80::";
$is = $this->ip->isInNetmask($testip, $testprefix, 16);
$this->assertTrue($is);
}
/**
* tests isInNetmask() with the netmask length in
* the second parameter
*/
public function testIsInNetmaskWithBitsInNetmask() {
$testip = "FE80:FFFF:0:FFFF:129:144:52:38";
$testprefix = "FE80::/16";
$is = $this->ip->isInNetmask($testip, $testprefix);
$this->assertTrue($is);
}
/**
* tests isInNetmask() with the netmask length in
* the first parameter
*/
public function testIsInNetmaskWithBitsInIP() {
$testip = "FE80:FFFF:0:FFFF:129:144:52:38/16";
$testprefix = "FE80::";
$is = $this->ip->isInNetmask($testip, $testprefix);
$this->assertTrue($is);
}
/**
* tests getNetmask with two parameters
*/
public function testGetNetmaskTwoParameters() {
$testip = "FE80:0:0:FFFF:129:144:52:38";
$is = $this->ip->getNetmask($testip, 16);
$this->assertEquals( "fe80:0:0:0:0:0:0:0", $is);
}
/**
* tests getNetmask with one parameter
*/
public function testGetNetmaskOneParameter() {
$testip = "FE80:0:0:FFFF:129:144:52:38/16";
$is = $this->ip->getNetmask($testip);
$this->assertEquals( "fe80:0:0:0:0:0:0:0", $is);
}
/**
* test getAddressType - Link Local
*/
public function testGetAddressTypeLinkLocal() {
$testip = "FE80:0:0:FFFF:129:144:52:38";
$is = $this->ip->getAddressType($testip);
$this->assertEquals( NET_IPV6_LOCAL_LINK, $is);
}
/**
* test getAddressType - Unassigned
*/
public function testGetAddressTypeUnassigned() {
$testip = "E000:0:0:FFFF:129:144:52:38";
$is = $this->ip->getAddressType($testip);
$this->assertEquals( NET_IPV6_UNASSIGNED, $is);
}
/**
* test the Bin2Ip method
*/
public function testBin2Ip() {
$testip = "1111111111111111".
"0000000000000000".
"0000000000000000".
"1111111111111111".
"0000000100101001".
"0000000101000100".
"0000000001010010".
"0000000000111000";
$_bin2Ip = self::getMethod("_bin2Ip");
$is = $_bin2Ip->invoke(null, $testip);
$this->assertEquals( "ffff:0:0:ffff:129:144:52:38", $is);
}
/**
* test the IP2Bin method with an uncompressed ip
*/
public function testIp2BinUncompressed() {
$testip = "ffff:0:0:FFFF:129:144:52:38";
$_ip2Bin = self::getMethod("_ip2Bin");
$is = $_ip2Bin->invoke(null, $testip);
$this->assertEquals( "1111111111111111".
"0000000000000000".
"0000000000000000".
"1111111111111111".
"0000000100101001".
"0000000101000100".
"0000000001010010".
"0000000000111000"
,$is);
}
/**
* test the IP2Bin method with a compressed ip
*/
public function testIp2BinCompressed() {
$testip = "ffff::FFFF:129:144:52:38";
$_ip2Bin = self::getMethod("_ip2Bin");
$is = $_ip2Bin->invoke(null, $testip);
$this->assertEquals( "1111111111111111".
"0000000000000000".
"0000000000000000".
"1111111111111111".
"0000000100101001".
"0000000101000100".
"0000000001010010".
"0000000000111000"
,$is);
}
/**
* this testcase handles Bug 13006
* compressing an IPv6 address with mixed IPv4 address gave wrong result.
*
*/
public function testBug13006_1() {
$testip = "2001:690:22c0:201::193.136.195.195";
$expected = "2001:690:22c0:201::193.136.195.195";
$is = $this->ip->compress($testip);
$this->assertEquals($expected, $is);
}
public function testBug13006_2() {
$testip = "2001:690:22c0:201::193.136.195.195";
$expected = "2001:690:22c0:201::193.136.195.195";
$is = $this->ip->compress($this->ip->uncompress($testip));
$this->assertEquals($expected, $is);
}
/**
* this testcase handles Bug 19334
* CheckIpv6 returned true because of an invalid check
* non-valid chars
*
*/
public function testBug19334() {
$testip = "fe80::16da:e9ff:fe0f:6dd4/64:48866";
$this->assertFalse($this->ip->checkIPv6($testip));
}
/**
* this testcase handles Bug 4977
* which covers the problem with wrong compressing where nothing is to
* compress and zeros are replaced by ':'
*
*/
public function testBug4977() {
$testip = "2001:ec8:1:1:1:1:1:1";
$is = $this->ip->compress($testip);
$this->assertEquals( "2001:ec8:1:1:1:1:1:1", $is);
}
/**
* this testcase handles Bug 3851
* which covers the problem with uncompressing with an IPv4 part
* in the ip
*
*/
public function testBug3851() {
$testip = "ffff::FFFF:129.144.52.38";
$is = $this->ip->uncompress($testip);
$this->assertEquals( "ffff:0:0:0:0:FFFF:129.144.52.38", $is);
}
/**
* this testcase handles Bug 3405
* which covers the problem with compressing 0000
* in the ip
*
*/
public function testBug3405() {
$testip = "2010:0588:0000:faef:1428:0000:0000:57ab";
$is = $this->ip->compress($testip);
$this->assertEquals( "2010:588:0:faef:1428::57ab", $is);
}
/**
* this testcase handles Bug 14747
* which covers already compressed adresses
* to keep as is
*/
public function testBug14747_CompressShouldDoNothingOnCompressedIPs() {
$testip = '2001:503:ba3e::2:30';
$is = $this->ip->compress($testip);
$this->assertEquals("2001:503:ba3e::2:30", $is);
$testip = 'ff01::101';
$is = $this->ip->compress($testip);
$this->assertEquals("ff01::101", $is);
}
/**
* this testcase handles Bug 2802
* which covers the problem with compressing 0000
* in the ip
*
*/
public function testBug2802() {
$testip = "0000:0000:0000:588:0000:FAEF:1428:57AB";
$is = $this->ip->compress($testip);
$this->assertEquals( "::588:0:faef:1428:57ab", $is);
}
/**
* this testcase handles Bug 2803
* which covers the problem adding a unnec. colon at the end
* in the ip
*
*/
public function testBug2803() {
$testip = "0:0:0:0588:0:FAEF:1428:57AB";
$is = $this->ip->compress($testip);
$this->assertEquals( "::588:0:faef:1428:57ab", $is);
}
/**
* handle Bug 12442
* Netmask is miss assigned during compression/uncompression
*/
public function testBug12442() {
$testip = "2001:4abc:abcd:0000:3744:0000:0000:0000/120";
$is = $this->ip->compress($testip);
$this->assertEquals( "2001:4abc:abcd:0:3744::/120", $is);
$testip = "2001:4abc:abcd:0:3744::/120";
$is = $this->ip->uncompress($testip);
$this->assertEquals( "2001:4abc:abcd:0:3744:0:0:0/120", $is);
}
/**
* handle Bug 15947
* checkIpv6 returns true although IP is too long
*/
public function testBug15947_IpTooLong() {
$testIp = '2001:0ec8:0000:0000:0000:0000:0000:0001111';
$is = $this->ip->checkIPv6($testIp);
$this->assertFalse($is);
}
/**
* handle Bug 18976
* checkIPv6 did not check the value of the netmask
*/
public function testBug18976_NetmaskValueOutOfRange() {
$testIp = '2002::/129';
$is = $this->ip->checkIPv6($testIp);
$this->assertFalse($is);
}
/**
* handle Bug 21046
* checkIPv6 wrongly validates IPv6 IPs with leading and/or trailing :
*/
public function testBug21046() {
$testIps = array(
'1234:5678:90AB:CDEF:1234:5678:90AB:CDEF:',
':1234:5678:90AB:CDEF:1234:5678:90AB:CDEF',
':1234:5678:90AB:CDEF:1234:5678:90AB:CDEF:'
);
foreach($testIps as $testIp) {
$is = $this->ip->checkIPv6($testIp);
$this->assertFalse($is);
}
}
/**
* handle Bug 21107 and 21106
* IP address validation issues
*/
public function testBug21107() {
$testIps = array(
"1:2:3:4:5:6:7:8:1.2.3.4",
"::1:2:3:4:5:6:7:8",
"1:2:3:4:5:6:7:8::",
"1:2:3:4:5:6:7:8:",
":1:2:3:4:5:6:7:8:",
":1:2:3:4:5:6:7:8",
"1:2:3:4:5:6:7:z",
"1:2:3:xy:5:6:7:8",
"gh:2:3:4:5:6:7:8",
"1:2:3:4:5:6:7:qw",
"1:2:3:4:5:6:7:z:a",
"1:2:3:xy:4:5:6:7:8",
"gh:1:2:3:xy:4:5:6:7:8",
"1:2:3:xy:4:5:6:7:8:qw",
"::::a",
"::::"
);
foreach($testIps as $testIp) {
$is = $this->ip->checkIPv6($testIp);
$this->assertFalse($is);
}
}
/**
* this testcase handles compress
*
*/
public function testCompress1() {
$testip = "FF01:0:0:0:0:0:0:101";
$is = $this->ip->compress($testip);
$this->assertEquals( "ff01::101", $is);
}
/**
* this testcase handles compress
*
*/
public function testCompress2() {
$testip = "0:0:0:0:0:0:0:1";
$is = $this->ip->compress($testip);
$this->assertEquals( "::1", $is);
}
/**
* this testcase handles compress
*
*/
public function testCompress3() {
$testip = "1:0:0:0:0:0:0:0";
$is = $this->ip->compress($testip);
$this->assertEquals( "1::", $is);
}
/**
* this testcase handles compressing the zero address
*
*/
public function testCompressZero() {
$testip = "0:0:0:0:0:0:0:0";
$is = $this->ip->compress($testip);
$this->assertEquals( "::", $is);
}
/**
* this testcase handles forced compression
*
*/
public function testCompressForced() {
$testip = "FF01::0:1";
$is = $this->ip->compress($testip, true);
$this->assertEquals( "ff01::1", $is);
}
/**
* this testcase handles compress with a prefix length spec
*
*/
public function testCompressWithPrefixLength() {
$testip = "0000:0000:0000:0000:0000:ffff:5056:5000/116";
$is = $this->ip->compress($testip);
$this->assertEquals( "::ffff:5056:5000/116", $is);
}
/**
* this testcase handles uncompress
*
*/
public function testUncompress1() {
$testip = "ff01::101";
$is = $this->ip->uncompress($testip);
$this->assertEquals( "ff01:0:0:0:0:0:0:101", $is);
}
/**
* this testcase handles uncompress
*
*/
public function testUncompress2() {
$testip = "::1";
$is = $this->ip->uncompress($testip);
$this->assertEquals( "0:0:0:0:0:0:0:1", $is);
}
/**
* this testcase handles uncompress
*
*/
public function testUncompress3() {
$testip = "1::";
$is = $this->ip->uncompress($testip);
$this->assertEquals( "1:0:0:0:0:0:0:0", $is);
}
/**
* this testcase handles uncompress with a prefix length spec
*
*/
public function testUncompressWithPrefixLength() {
$testip = "::ffff:5056:5000/116";
$is = $this->ip->uncompress($testip);
$this->assertEquals( "0:0:0:0:0:ffff:5056:5000/116", $is);
}
/**
* this testcase handles uncompress adding leading zeros
*
*/
public function testUncompress1WithLeadingZeros() {
$testip = "ff01::101";
$is = $this->ip->uncompress($testip, true);
$this->assertEquals( "ff01:0000:0000:0000:0000:0000:0000:0101", $is);
}
/**
* this testcase handles uncompress adding leading zeros
*
*/
public function testUncompress2WithLeadingZeros() {
$testip = "::1";
$is = $this->ip->uncompress($testip, true);
$this->assertEquals( "0000:0000:0000:0000:0000:0000:0000:0001", $is);
}
/**
* this testcase handles uncompress adding leading zeros
*
*/
public function testUncompress3WithLeadingZeros() {
$testip = "1::";
$is = $this->ip->uncompress($testip, true);
$this->assertEquals( "0001:0000:0000:0000:0000:0000:0000:0000", $is);
}
/**
* this testcase handles uncompress with a prefix length spec adding leading zeros
*
*/
public function testUncompressWithPrefixLengthWithLeadingZeros() {
$testip = "::ffff:5056:5000/116";
$is = $this->ip->uncompress($testip, true);
$this->assertEquals( "0000:0000:0000:0000:0000:ffff:5056:5000/116", $is);
}
/**
* this testcase handles get Prefix length
*
*/
public function testGetPrefixLength() {
$testip = "0000:0000:0000:0000:0000:ffff:5056:5000/116";
$prefix = $this->ip->getPrefixLength($testip);
$this->assertEquals( "116", $prefix);
}
/**
* this testcase handles remove a Prefix length
*
*/
public function testRemovePrefixLength() {
$testip = "0000:0000:0000:0000:0000:ffff:5056:5000/116";
$ip = $this->ip->removePrefixLength($testip);
$this->assertEquals( "0000:0000:0000:0000:0000:ffff:5056:5000", $ip);
}
public function testParseAddress() {
$testip = "2001:502:f3ff::/48";
$result = $this->ip->parseAddress($testip);
$this->assertEquals( "2001:502:f3ff:0:0:0:0:0", $result['start']);
$this->assertEquals( "2001:502:f3ff:ffff:ffff:ffff:ffff:ffff", $result['end']);
}
/**
* related to bug #21140
* @author phildavis
*/
public function testSplitV64Normal() {
$testip = "abcd:2:3:4:5:6:13.1.68.3";
$result = $this->ip->SplitV64($testip);
$this->assertEquals( "abcd:2:3:4:5:6", $result[0]);
$this->assertEquals( "13.1.68.3", $result[1]);
}
/**
* related to bug #21140
* @author phildavis
*/
public function testSplitV64Uncompress() {
$testip = "abcd::6:13.1.68.3";
$result = $this->ip->SplitV64($testip);
$this->assertEquals( "abcd:0:0:0:0:6", $result[0]);
$this->assertEquals( "13.1.68.3", $result[1]);
}
/**
* related to bug #21140
* @author phildavis
*/
public function testSplitV64UncompressDoubleColon() {
$testip = "::13.1.68.3";
$result = $this->ip->SplitV64($testip);
$this->assertEquals( "0:0:0:0:0:0", $result[0]);
$this->assertEquals( "13.1.68.3", $result[1]);
}
/**
* related to bug #21140
* @author phildavis
*/
public function testSplitV64UncompressDoubleColonAtEnd() {
$testip = "abcd:2::13.1.68.3";
$result = $this->ip->SplitV64($testip);
$this->assertEquals( "abcd:2:0:0:0:0", $result[0]);
$this->assertEquals( "13.1.68.3", $result[1]);
}
/**
* related to bug #21140
* @author phildavis
*/
public function testSplitV64UncompressDoubleColonAtStart() {
$testip = "::ffff:13.1.68.3";
$result = $this->ip->SplitV64($testip);
$this->assertEquals( "0:0:0:0:0:ffff", $result[0]);
$this->assertEquals( "13.1.68.3", $result[1]);
}
/**
* related to bug #21140
* @author phildavis
*/
public function testSplitV64DoNotUncompress() {
$testip = "abcd::6:13.1.68.3";
$result = $this->ip->SplitV64($testip, false);
$this->assertEquals( "abcd::6", $result[0]);
$this->assertEquals( "13.1.68.3", $result[1]);
}
/**
* related to bug #21140
* @author phildavis
*/
public function testSplitV64DoNotUncompressDoubleColon() {
$testip = "::13.1.68.3";
$result = $this->ip->SplitV64($testip, false);
$this->assertEquals( "::", $result[0]);
$this->assertEquals( "13.1.68.3", $result[1]);
}
/**
* related to bug #21140
* @author phildavis
*/
public function testSplitV64DoNotUncompressDoubleColonAtEnd() {
$testip = "abcd:2::13.1.68.3";
$result = $this->ip->SplitV64($testip, false);
$this->assertEquals( "abcd:2::", $result[0]);
$this->assertEquals( "13.1.68.3", $result[1]);
}
/**
* related to bug #21140
* @author phildavis
*/
public function testSplitV64DoNotUncompressDoubleColonAtStart() {
$testip = "::ffff:13.1.68.3";
$result = $this->ip->SplitV64($testip, false);
$this->assertEquals( "::ffff", $result[0]);
$this->assertEquals( "13.1.68.3", $result[1]);
}
/**
* related to bug #21140
* @author phildavis
*/
public function testSplitV64IPv4Only() {
$testip = "13.1.68.3";
$result = $this->ip->SplitV64($testip);
$this->assertEquals( "", $result[0]);
$this->assertEquals( "13.1.68.3", $result[1]);
}
/**
* related to bug #21140
* @author phildavis
*/
public function testSplitV64IPv6Only() {
$testip = "a:b:c:d:e:f:1:2";
$result = $this->ip->SplitV64($testip);
$this->assertEquals( "a:b:c:d:e:f:1:2", $result[0]);
$this->assertEquals( "", $result[1]);
}
/**
* related to bug #23756
* @author landy
*/
public function testCompressedNetmasksIncorrectlyDetectedInIsInNetmask() {
$netmask = '::ffff/96';
$testip = '0:0:0:0:0:ffff:c000:22f';
$this->assertTrue(Net_IPv6::isInNetmask($testip, $netmask));
}
}