Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F1715
ipv6.patch
Public
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Authored By
•
bzimport
Nov 21 2014, 8:01 PM
2014-11-21 20:01:01 (UTC+0)
Size
6 KB
Referenced Files
None
Subscribers
None
ipv6.patch
View Options
Index: IP.php
===================================================================
--- IP.php (revision 20333)
+++ IP.php (working copy)
@@ -23,6 +23,134 @@
class IP {
/**
+ * Given an IP address in dotted-quad notation, returns an IPv6 octet.
+ * See http://www.answers.com/topic/ipv4-compatible-address
+ * IPs with the first 92 bits as zeros are reserved from IPv6
+ * @param $ip quad-dotted IP address.
+ * @return string
+ */
+ public function IPv4toIPv6( $ip ) {
+ if ( !$ip ) return null;
+ // Convert only if needed
+ if ( strpos($ip,':') !==false ) return $ip;
+ return IP::toOctet( IP::toUnsigned( $ip ) );
+ }
+
+ /**
+ * Given an IPv6 address in octet notation, returns an unsigned integer.
+ * @param $ip octet ipv6 IP address.
+ * @return base 10 integer
+ */
+ public function toUnsigned6( $ip ) {
+ $ip = explode(':', IP::expandIPv6( $ip ) );
+ $r_ip = '';
+ foreach ($ip as $v) {
+ $r_ip .= wfBaseConvert( $v, 16, 2, 16);
+ }
+ return wfBaseConvert($r_ip, 2, 10);
+ }
+
+ /**
+ * Given an IPv6 address in octet notation, returns the expanded octet.
+ * @param $ip octet ipv6 IP address.
+ * @return string
+ */
+ public function expandIPv6( $ip ) {
+ // Expand zero abbreviations
+ if (substr_count($ip, '::')) {
+ $ip = str_replace('::', str_repeat(':0000', 8 - substr_count($ip, ':')) . ':', $ip);
+ }
+ return "$ip";
+ }
+
+ /**
+ * Given an unsigned integer, returns an IPv6 address in octet notation
+ * @param $ip integer ipv6 IP address.
+ * @return string
+ */
+ public function toOctet( $ip_int ) {
+ // Convert integer to binary
+ $ip_int = wfBaseConvert($ip_int, 10, 2, 128);
+ // Seperate into 8 octets
+ $ip_oct = base_convert( substr( $ip_int, 0, 16 ), 2, 16 );
+ for ($n=1; $n < 8; $n++) {
+ // Convert to hex, and add ":" marks
+ $ip_oct .= ':' . base_convert( substr($ip_int, 16*$n, 16), 2, 16 );
+ }
+ return "$ip_oct";
+ }
+
+ /**
+ * Convert a network specification in CIDR notation to an integer network and a number of bits
+ * @return array(int, int)
+ */
+ public static function parseCIDR6( $range ) {
+ $parts = explode( '/', $range, 2 );
+ if ( count( $parts ) != 2 ) {
+ return array( false, false );
+ }
+ $network = IP::toUnsigned6( $parts[0] );
+ if ( $network !== false && is_numeric( $parts[1] ) && $parts[1] >= 0 && $parts[1] <= 128 ) {
+ $bits = $parts[1];
+ if ( $bits == 0 ) {
+ $network = 0;
+ } else {
+ # Truncate the last (128-$bits) bits, turn them into zeros
+ # Native 32 bit functions WONT work here!!!
+ $network = wfBaseConvert( $network, 10, 2, 128 );
+ $network = str_pad( substr( $network, 0, (128 - $bits) ), 128, 0, STR_PAD_RIGHT );
+ $network = wfBaseConvert( $network, 2, 10 );
+ }
+ } else {
+ $network = false;
+ $bits = false;
+ }
+
+ return array( $network, $bits );
+ }
+
+ /**
+ * Given a string range in a number of formats, return the start and end of
+ * the range in hexadecimal. For IPv6.
+ *
+ * Formats are:
+ * 2001:0db8:85a3::7344/96 CIDR
+ * 2001:0db8:85a3::7344 - 2001:0db8:85a3::7344 Explicit range
+ * 2001:0db8:85a3::7344/96 Single IP
+ * @return array(int, int)
+ */
+ public static function parseRange6( $range ) {
+ if ( strpos( $range, '/' ) !== false ) {
+ # CIDR
+ list( $network, $bits ) = IP::parseCIDR6( $range );
+ if ( $network === false ) {
+ $start = $end = false;
+ } else {
+ $start = sprintf( '%08X', $network );
+ $end = sprintf( '%08X', $network + pow( 2, (128 - $bits) ) - 1 );
+ }
+ } elseif ( strpos( $range, '-' ) !== false ) {
+ # Explicit range
+ list( $start, $end ) = array_map( 'trim', explode( '-', $range, 2 ) );
+ $start = IP::toUnsigned6( $start ); $end = IP::toUnsigned6( $end );
+ if ( $start > $end ) {
+ $start = $end = false;
+ } else {
+ $start = sprintf( '%08X', $start );
+ $end = sprintf( '%08X', $end );
+ }
+ } else {
+ # Single IP
+ $start = $end = IP::toHex6( $range );
+ }
+ if ( $start === false || $end === false ) {
+ return array( false, false );
+ } else {
+ return array( $start, $end );
+ }
+ }
+
+ /**
* Validate an IP address.
* @return boolean True if it is valid.
*/
@@ -101,6 +229,7 @@
* hexadecimal string which sorts after the IPv4 addresses.
*
* @param $ip Quad dotted IP address.
+ * @return hexidecimal
*/
public static function toHex( $ip ) {
$n = self::toUnsigned( $ip );
@@ -109,12 +238,22 @@
}
return $n;
}
+
+ // For IPv6
+ public static function toHex6( $ip ) {
+ $n = self::toUnsigned6( $ip );
+ if ( $n !== false ) {
+ $n = sprintf( '%08X', $n );
+ }
+ return $n;
+ }
/**
* Given an IP address in dotted-quad notation, returns an unsigned integer.
* Like ip2long() except that it actually works and has a consistent error return value.
* Comes from ProxyTools.php
* @param $ip Quad dotted IP address.
+ * @return integer
*/
public static function toUnsigned( $ip ) {
if ( $ip == '255.255.255.255' ) {
@@ -149,6 +288,7 @@
/**
* Convert a network specification in CIDR notation to an integer network and a number of bits
+ * @return array(int, int)
*/
public static function parseCIDR( $range ) {
$parts = explode( '/', $range, 2 );
@@ -176,12 +316,13 @@
/**
* Given a string range in a number of formats, return the start and end of
- * the range in hexadecimal.
+ * the range in hexadecimal. For IPv4.
*
* Formats are:
* 1.2.3.4/24 CIDR
* 1.2.3.4 - 1.2.3.5 Explicit range
* 1.2.3.4 Single IP
+ * @return array(int, int)
*/
public static function parseRange( $range ) {
if ( strpos( $range, '/' ) !== false ) {
@@ -196,11 +337,12 @@
} elseif ( strpos( $range, '-' ) !== false ) {
# Explicit range
list( $start, $end ) = array_map( 'trim', explode( '-', $range, 2 ) );
+ $start = IP::toUnsigned( $start ); $end = IP::toUnsigned( $end );
if ( $start > $end ) {
$start = $end = false;
} else {
- $start = IP::toHex( $start );
- $end = IP::toHex( $end );
+ $start = sprintf( '%08X', $start );
+ $end = sprintf( '%08X', $end );
}
} else {
# Single IP
@@ -220,8 +362,9 @@
* @return bool Whether or not the given address is in the given range.
*/
public static function isInRange( $addr, $range ) {
- $unsignedIP = IP::toUnsigned($addr);
- list( $start, $end ) = IP::parseRange($range);
+ // Conver to IPv6 if needed
+ $unsignedIP = IP::toUnsigned6( IP::IPv4toIPv6($addr) );
+ list( $start, $end ) = IP::parseRange6($range);
$start = hexdec($start);
$end = hexdec($end);
File Metadata
Details
Attached
Mime Type
text/x-diff
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1298
Default Alt Text
ipv6.patch (6 KB)
Attached To
Mode
T3196: Add basic IPv6 support in core
Attached
Detach File
Event Timeline
Log In to Comment