Page MenuHomePhabricator

ipv6.patch

Authored By
bzimport
Nov 21 2014, 8:01 PM
Size
6 KB
Referenced Files
None
Subscribers
None

ipv6.patch

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

Mime Type
text/x-diff
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1298
Default Alt Text
ipv6.patch (6 KB)

Event Timeline