Page MenuHomePhabricator

D16984.diff
No OneTemporary

D16984.diff

diff --git a/src/ip/PhutilCIDRBlock.php b/src/ip/PhutilCIDRBlock.php
--- a/src/ip/PhutilCIDRBlock.php
+++ b/src/ip/PhutilCIDRBlock.php
@@ -16,28 +16,27 @@
public static function newBlock($in) {
if ($in instanceof PhutilCIDRBlock) {
- return $in;
+ return clone $in;
}
return self::newFromString($in);
}
private static function newFromString($str) {
- if (!preg_match('(^[\d.]+/[\d]+\z)', $str)) {
+ if (!preg_match('(^[\d.:a-fA-F]+/[\d]+\z)', $str)) {
throw new Exception(
pht(
'CIDR block "%s" is not formatted correctly. Expected an IP block '.
- 'in CIDR notation, like "%s".',
+ 'in CIDR notation, like "%s" or "%s".',
$str,
- '172.30.0.0/16'));
+ '172.30.0.0/16',
+ '23:45:67:89::/24'));
}
list($ip, $mask) = explode('/', $str);
$ip = PhutilIPAddress::newAddress($ip);
- // These rules are for IPv4; some day we'll handle IPv6 too.
-
if (preg_match('/^0\d/', $mask)) {
throw new Exception(
pht(
@@ -47,14 +46,17 @@
$mask));
}
+ $max_bits = $ip->getBitCount();
+
$bits = (int)$mask;
- if ($bits < 0 || $bits > 32) {
+ if ($bits < 0 || $bits > $max_bits) {
throw new Exception(
pht(
'CIDR block "%s" is not formatted correctly. The IP block mask '.
- '("%s") must mask between 0 and 32 bits, inclusive.',
+ '("%s") must mask between 0 and %s bits, inclusive.',
$str,
- $mask));
+ $mask,
+ new PhutilNumber($max_bits)));
}
$obj = new PhutilCIDRBlock();
@@ -70,6 +72,12 @@
$block_bits = $this->ip->toBits();
$address_bits = $address->toBits();
+ // If the two addresses have different bit widths (IPv4 vs IPv6), this
+ // CIDR block does not match the address.
+ if ($this->ip->getBitCount() != $address->getBitCount()) {
+ return false;
+ }
+
return (strncmp($block_bits, $address_bits, $this->bits) === 0);
}
diff --git a/src/ip/PhutilIPAddress.php b/src/ip/PhutilIPAddress.php
--- a/src/ip/PhutilIPAddress.php
+++ b/src/ip/PhutilIPAddress.php
@@ -11,6 +11,7 @@
}
abstract public function toBits();
+ abstract public function getBitCount();
abstract public function getAddress();
public static function newAddress($in) {
diff --git a/src/ip/PhutilIPv4Address.php b/src/ip/PhutilIPv4Address.php
--- a/src/ip/PhutilIPv4Address.php
+++ b/src/ip/PhutilIPv4Address.php
@@ -16,6 +16,10 @@
return $this->ip;
}
+ public function getBitCount() {
+ return 32;
+ }
+
protected static function newFromString($str) {
$matches = null;
$ok = preg_match('(^(\d+)\.(\d+)\.(\d+).(\d+)\z)', $str, $matches);
diff --git a/src/ip/PhutilIPv6Address.php b/src/ip/PhutilIPv6Address.php
--- a/src/ip/PhutilIPv6Address.php
+++ b/src/ip/PhutilIPv6Address.php
@@ -13,6 +13,10 @@
// <private>
}
+ public function getBitCount() {
+ return 128;
+ }
+
protected static function newFromString($str) {
$parts = explode(':', $str);
if (count($parts) > 8) {
diff --git a/src/ip/__tests__/PhutilIPAddressTestCase.php b/src/ip/__tests__/PhutilIPAddressTestCase.php
--- a/src/ip/__tests__/PhutilIPAddressTestCase.php
+++ b/src/ip/__tests__/PhutilIPAddressTestCase.php
@@ -182,7 +182,7 @@
}
}
- public function testValidCIDRBlocks() {
+ public function testValidIPv4CIDRBlocks() {
$cases = array(
// Valid block.
'1.0.0.0/16' => true,
@@ -217,23 +217,87 @@
}
}
- public function testCIDRBlockContains() {
+ public function testValidIPv6CIDRBlocks() {
+ $cases = array(
+ // Valid block.
+ '::/16' => true,
+ '::/128' => true,
+
+ // No nonsense.
+ '::/1/2' => false,
+ '::/::' => false,
+ '::' => false,
+
+ // No leading zeroes.
+ '::/01' => false,
+
+ // No out-of-range masks.
+ '::/129' => false,
+ );
+
+ foreach ($cases as $input => $expect) {
+ $caught = null;
+ try {
+ PhutilCIDRBlock::newBlock($input);
+ } catch (Exception $ex) {
+ $caught = $ex;
+ }
+
+ $this->assertEqual(
+ $expect,
+ !($caught instanceof Exception),
+ 'PhutilCIDRBlock['.$input.']');
+ }
+ }
+
+ public function testIPv4CIDRBlockContains() {
$cases = array(
'0.0.0.0/0' => array(
'0.0.0.0' => true,
'1.1.1.1' => true,
'2.3.4.5' => true,
+ '::' => false,
+ '::1' => false,
+ '::ffff:0:0' => false,
),
'0.0.0.2/32' => array(
'0.0.0.1' => false,
'0.0.0.2' => true,
'0.0.0.3' => false,
+ '::' => false,
),
'172.30.0.0/16' => array(
'172.29.255.255' => false,
'172.30.0.0' => true,
'172.30.255.255' => true,
'172.31.0.0' => false,
+ '::' => false,
+ ),
+ );
+
+ foreach ($cases as $input_block => $tests) {
+ $block = PhutilCIDRBlock::newBlock($input_block);
+ foreach ($tests as $input => $expect) {
+ $this->assertEqual(
+ $expect,
+ $block->containsAddress($input),
+ 'PhutilCIDRBlock['.$input_block.']->containsAddress('.$input.')');
+ }
+ }
+ }
+
+ public function testIPv6CIDRBlockContains() {
+ $cases = array(
+ '::/0' => array(
+ '1::' => true,
+ '2::' => true,
+ '127.0.0.1' => false,
+ ),
+ '::ffff:0:0/96' => array(
+ '::ffff:0:0' => true,
+ '::ffff:ffff:ffff' => true,
+ '::fffe:0:0' => false,
+ '127.0.0.1' => false,
),
);

File Metadata

Mime Type
text/plain
Expires
Sat, May 18, 7:35 AM (2 w, 4 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6297960
Default Alt Text
D16984.diff (5 KB)

Event Timeline