fix: Merge adjacent CIDRs

This commit is contained in:
Rekryt
2024-11-02 05:23:56 +03:00
parent 9957cd8dd2
commit 09812cd3e8
4 changed files with 58 additions and 33 deletions

View File

@@ -145,15 +145,15 @@ final class Site {
if (isset($this->external->cidr4) && $this->isUseIpv4) {
foreach ($this->external->cidr4 as $url) {
$this->cidr4 = SiteFactory::normalize(
array_merge($this->cidr4, explode("\n", file_get_contents($url))),
true
$this->cidr4 = IP4Helper::minimizeSubnets(
SiteFactory::normalize(array_merge($this->cidr4, explode("\n", file_get_contents($url))), true)
);
}
}
if (isset($this->external->cidr6) && $this->isUseIpv6) {
foreach ($this->external->cidr6 as $url) {
// todo IP6Helper::minimizeSubnets
$this->cidr6 = SiteFactory::normalize(
array_merge($this->cidr6, explode("\n", file_get_contents($url))),
true

View File

@@ -3,10 +3,12 @@
namespace OpenCCK\Domain\Factory;
use OpenCCK\Domain\Entity\Site;
use OpenCCK\Domain\Helper\IP4Helper;
use OpenCCK\Domain\Helper\IP6Helper;
use OpenCCK\Infrastructure\API\App;
use stdClass;
use function \OpenCCK\getEnv;
use function OpenCCK\getEnv;
class SiteFactory {
// prettier-ignore
@@ -78,8 +80,8 @@ class SiteFactory {
$domains = self::normalize($domains);
$ip4 = self::normalize($ip4, true);
$ip6 = self::normalize($ip6, true);
$cidr4 = self::normalize($cidr4, true);
$cidr6 = self::normalize($cidr6, true);
$cidr4 = IP4Helper::minimizeSubnets(self::normalize($cidr4, true));
$cidr6 = self::normalize($cidr6, true); //$cidr6 = IP6Helper::minimizeSubnets(self::normalize($cidr6, true));
return new Site($name, $group, $domains, $dns, $timeout, $ip4, $ip6, $cidr4, $cidr6, $external);
}

View File

@@ -22,7 +22,7 @@ class IP4Helper {
if (CIDRStorage::getInstance()->has($ip)) {
$searchArray = CIDRStorage::getInstance()->get($ip);
$results = array_merge($results, self::trimCIDRs($searchArray));
$results = array_merge($results, $searchArray);
App::getLogger()->debug($ip . ' -> ' . json_encode($searchArray), [
$i + 1 . '/' . $count,
@@ -72,8 +72,12 @@ class IP4Helper {
explode(' ', strtr($search, ' ', '')),
fn(string $cidr) => strlen($cidr) > 0
);
$searchArray = array_values(
array_filter(self::trimCIDRs($searchArray), fn($cidr) => self::isInCIDR($ip, $cidr))
);
CIDRStorage::getInstance()->set($ip, $searchArray);
$results = array_merge($results, self::trimCIDRs($searchArray));
$results = array_merge($results, $searchArray);
App::getLogger()->debug($ip . ' -> ' . json_encode($searchArray), [$i + 1 . '/' . $count, 'found']);
} else {
@@ -135,10 +139,17 @@ class IP4Helper {
return $result;
}
public static function isInCIDR(string $ip, string $cidr): bool {
[$subnet, $mask] = explode('/', $cidr);
if ((ip2long($ip) & ~((1 << 32 - $mask) - 1)) === ip2long($subnet)) {
return true;
}
return false;
}
public static function isInRange(string $ip, array $cidrs): bool {
foreach ($cidrs as $cidr) {
[$subnet, $mask] = explode('/', $cidr);
if ((ip2long($ip) & ~((1 << 32 - $mask) - 1)) === ip2long($subnet)) {
if (self::isInCIDR($ip, $cidr)) {
return true;
}
}

View File

@@ -22,7 +22,7 @@ class IP6Helper {
if (CIDRStorage::getInstance()->has($ip)) {
$searchArray = CIDRStorage::getInstance()->get($ip);
$results = array_merge($results, self::trimCIDRs($searchArray));
$results = array_merge($results, $searchArray);
App::getLogger()->debug($ip . ' -> ' . json_encode($searchArray), [
$i + 1 . '/' . $count,
@@ -72,8 +72,12 @@ class IP6Helper {
explode(' ', strtr($search, ' ', '')),
fn(string $cidr) => strlen($cidr) > 0
);
$searchArray = array_values(
array_filter(self::trimCIDRs($searchArray), fn($cidr) => self::isInCIDR($ip, $cidr))
);
CIDRStorage::getInstance()->set($ip, $searchArray);
$results = array_merge($results, self::trimCIDRs($searchArray));
$results = array_merge($results, $searchArray);
App::getLogger()->debug($ip . ' -> ' . json_encode($searchArray), [$i + 1 . '/' . $count, 'found']);
} else {
@@ -160,30 +164,38 @@ class IP6Helper {
return $result;
}
public static function isInRange(string $ip, array $cidrs): bool {
public static function isInCidr(string $ip, string $cidr): bool {
$ip = inet_pton($ip);
[$subnet, $mask] = explode('/', $cidr);
$subnet = inet_pton($subnet);
$mask = intval($mask);
$binaryMask = str_repeat('f', $mask >> 2);
switch ($mask % 4) {
case 1:
$binaryMask .= '8';
break;
case 2:
$binaryMask .= 'c';
break;
case 3:
$binaryMask .= 'e';
break;
}
$binaryMask = str_pad($binaryMask, 32, '0');
$mask = pack('H*', $binaryMask);
if (($ip & $mask) === ($subnet & $mask)) {
return true;
}
return false;
}
public static function isInRange(string $ip, array $cidrs): bool {
foreach ($cidrs as $cidr) {
[$subnet, $mask] = explode('/', $cidr);
$subnet = inet_pton($subnet);
$mask = intval($mask);
$binaryMask = str_repeat('f', $mask >> 2);
switch ($mask % 4) {
case 1:
$binaryMask .= '8';
break;
case 2:
$binaryMask .= 'c';
break;
case 3:
$binaryMask .= 'e';
break;
}
$binaryMask = str_pad($binaryMask, 32, '0');
$mask = pack('H*', $binaryMask);
if (($ip & $mask) === ($subnet & $mask)) {
if (self::isInCIDR($ip, $cidr)) {
return true;
}
}