diff --git a/src/Control/Util/IPUtils.php b/src/Control/Util/IPUtils.php deleted file mode 100644 index 8d6039ad317..00000000000 --- a/src/Control/Util/IPUtils.php +++ /dev/null @@ -1,175 +0,0 @@ - - */ - -namespace SilverStripe\Control\Util; - -use SilverStripe\Dev\Deprecation; - -/** - * Http utility functions. - * - * @author Fabien Potencier - * @deprecated 5.3.0 Use Symfony\Component\HttpFoundation\IpUtils instead - */ -class IPUtils -{ - /** - * This class should not be instantiated. - */ - private function __construct() - { - } - /** - * Checks if an IPv4 or IPv6 address is contained in the list of given IPs or subnets. - * - * @param string $requestIP IP to check - * @param string|array $ips List of IPs or subnets (can be a string if only a single one) - * - * @return bool Whether the IP is valid - * - * @package framework - * @subpackage core - */ - public static function checkIP($requestIP, $ips) - { - Deprecation::notice('5.3.0', 'Use Symfony\Component\HttpFoundation\IpUtils::checkIP() instead'); - if (!is_array($ips)) { - $ips = [$ips]; - } - - $method = substr_count($requestIP ?? '', ':') > 1 ? 'checkIP6' : 'checkIP4'; - - foreach ($ips as $ip) { - if (IPUtils::$method($requestIP, trim($ip ?? ''))) { - return true; - } - } - - return false; - } - /** - * Compares two IPv4 addresses. - * In case a subnet is given, it checks if it contains the request IP. - * - * @param string $requestIP IPv4 address to check - * @param string $ip IPv4 address or subnet in CIDR notation - * - * @return bool Whether the request IP matches the IP, or whether the request IP is within the CIDR subnet - */ - public static function checkIP4($requestIP, $ip) - { - Deprecation::notice('5.3.0', 'Use Symfony\Component\HttpFoundation\IpUtils::checkIP4() instead'); - if (!filter_var($requestIP, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { - return false; - } - - if (false !== strpos($ip ?? '', '/')) { - list($address, $netmask) = explode('/', $ip ?? '', 2); - - if ($netmask === '0') { - return filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4); - } - - if ($netmask < 0 || $netmask > 32) { - return false; - } - } else { - $address = $ip; - $netmask = 32; - } - - return 0 === substr_compare(sprintf('%032b', ip2long($requestIP ?? '')), sprintf('%032b', ip2long($address ?? '')), 0, $netmask); - } - /** - * Compares two IPv6 addresses. - * In case a subnet is given, it checks if it contains the request IP. - * - * @author David Soria Parra - * - * @see https://github.com/dsp/v6tools - * - * @param string $requestIP IPv6 address to check - * @param string $ip IPv6 address or subnet in CIDR notation - * - * @return bool Whether the IP is valid - * - * @throws \RuntimeException When IPV6 support is not enabled - */ - public static function checkIP6($requestIP, $ip) - { - Deprecation::notice('5.3.0', 'Use Symfony\Component\HttpFoundation\IpUtils::checkIP6() instead'); - if (!((extension_loaded('sockets') && defined('AF_INET6')) || @inet_pton('::1'))) { - throw new \RuntimeException('Unable to check IPv6. Check that PHP was not compiled with option "disable-ipv6".'); - } - - if (false !== strpos($ip ?? '', '/')) { - list($address, $netmask) = explode('/', $ip ?? '', 2); - - if ($netmask < 1 || $netmask > 128) { - return false; - } - } else { - $address = $ip; - $netmask = 128; - } - - $bytesAddr = unpack('n*', @inet_pton($address ?? '')); - $bytesTest = unpack('n*', @inet_pton($requestIP ?? '')); - - if (!$bytesAddr || !$bytesTest) { - return false; - } - - for ($i = 1, $ceil = ceil($netmask / 16); $i <= $ceil; ++$i) { - $left = $netmask - 16 * ($i - 1); - $left = ($left <= 16) ? $left : 16; - $mask = ~(0xffff >> $left) & 0xffff; - if (($bytesAddr[$i] & $mask) != ($bytesTest[$i] & $mask)) { - return false; - } - } - - return true; - } - - /** - * Anonymizes an IP/IPv6. - * - * Removes the last byte for v4 and the last 8 bytes for v6 IPs - */ - public static function anonymize(string $ip): string - { - Deprecation::notice('5.3.0', 'Use Symfony\Component\HttpFoundation\IpUtils::anonymize() instead'); - $wrappedIPv6 = false; - if (str_starts_with($ip, '[') && str_ends_with($ip, ']')) { - $wrappedIPv6 = true; - $ip = substr($ip, 1, -1); - } - - $packedAddress = inet_pton($ip); - if (4 === \strlen($packedAddress)) { - $mask = '255.255.255.0'; - } elseif ($ip === inet_ntop($packedAddress & inet_pton('::ffff:ffff:ffff'))) { - $mask = '::ffff:ffff:ff00'; - } elseif ($ip === inet_ntop($packedAddress & inet_pton('::ffff:ffff'))) { - $mask = '::ffff:ff00'; - } else { - $mask = 'ffff:ffff:ffff:ffff:0000:0000:0000:0000'; - } - $ip = inet_ntop($packedAddress & inet_pton($mask)); - - if ($wrappedIPv6) { - $ip = '[' . $ip . ']'; - } - - return $ip; - } -} diff --git a/tests/php/Control/IPUtilsTest.php b/tests/php/Control/IPUtilsTest.php deleted file mode 100644 index 8b0ddfe4697..00000000000 --- a/tests/php/Control/IPUtilsTest.php +++ /dev/null @@ -1,92 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -use SilverStripe\Dev\SapphireTest; -use SilverStripe\Control\Util\IPUtils; -use SilverStripe\Dev\Deprecation; - -class IPUtilsTest extends SapphireTest -{ - /** - * @dataProvider iPv4Provider - */ - public function testIPv4($matches, $remoteAddr, $cidr) - { - Deprecation::withNoReplacement(function () use ($matches, $remoteAddr, $cidr) { - $this->assertSame($matches, IPUtils::checkIP($remoteAddr, $cidr)); - }); - } - - public function iPv4Provider() - { - return [ - [true, '192.168.1.1', '192.168.1.1'], - [true, '192.168.1.1', '192.168.1.1/1'], - [true, '192.168.1.1', '192.168.1.0/24'], - [false, '192.168.1.1', '1.2.3.4/1'], - [false, '192.168.1.1', '192.168.1.1/33'], // invalid subnet - [true, '192.168.1.1', ['1.2.3.4/1', '192.168.1.0/24']], - [true, '192.168.1.1', ['192.168.1.0/24', '1.2.3.4/1']], - [false, '192.168.1.1', ['1.2.3.4/1', '4.3.2.1/1']], - [true, '1.2.3.4', '0.0.0.0/0'], - [true, '1.2.3.4', '192.168.1.0/0'], - [false, '1.2.3.4', '256.256.256/0'], // invalid CIDR notation - [false, 'an_invalid_ip', '192.168.1.0/24'], - ]; - } - - /** - * @dataProvider iPv6Provider - */ - public function testIPv6($matches, $remoteAddr, $cidr) - { - if (!defined('AF_INET6')) { - $this->markTestSkipped('Only works when PHP is compiled without the option "disable-ipv6".'); - } - - Deprecation::withNoReplacement(function () use ($matches, $remoteAddr, $cidr) { - $this->assertSame($matches, IPUtils::checkIP($remoteAddr, $cidr)); - }); - } - - public function iPv6Provider() - { - return [ - [true, '2a01:198:603:0:396e:4789:8e99:890f', '2a01:198:603:0::/65'], - [false, '2a00:198:603:0:396e:4789:8e99:890f', '2a01:198:603:0::/65'], - [false, '2a01:198:603:0:396e:4789:8e99:890f', '::1'], - [true, '0:0:0:0:0:0:0:1', '::1'], - [false, '0:0:603:0:396e:4789:8e99:0001', '::1'], - [true, '2a01:198:603:0:396e:4789:8e99:890f', ['::1', '2a01:198:603:0::/65']], - [true, '2a01:198:603:0:396e:4789:8e99:890f', ['2a01:198:603:0::/65', '::1']], - [false, '2a01:198:603:0:396e:4789:8e99:890f', ['::1', '1a01:198:603:0::/65']], - [false, '}__test|O:21:"JDatabaseDriverMysqli":3:{s:2', '::1'], - [false, '2a01:198:603:0:396e:4789:8e99:890f', 'unknown'], - ]; - } - - /** - * @requires extension sockets - */ - public function testAnIPv6WithOptionDisabledIPv6() - { - $this->expectException(\RuntimeException::class); - if (defined('AF_INET6')) { - $this->markTestSkipped('Only works when PHP is compiled with the option "disable-ipv6".'); - } - - Deprecation::withNoReplacement(function () { - IPUtils::checkIP('2a01:198:603:0:396e:4789:8e99:890f', '2a01:198:603:0::/65'); - }); - } -}