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) { if (isset($this->external->cidr4) && $this->isUseIpv4) {
foreach ($this->external->cidr4 as $url) { foreach ($this->external->cidr4 as $url) {
$this->cidr4 = SiteFactory::normalize( $this->cidr4 = IP4Helper::minimizeSubnets(
array_merge($this->cidr4, explode("\n", file_get_contents($url))), SiteFactory::normalize(array_merge($this->cidr4, explode("\n", file_get_contents($url))), true)
true
); );
} }
} }
if (isset($this->external->cidr6) && $this->isUseIpv6) { if (isset($this->external->cidr6) && $this->isUseIpv6) {
foreach ($this->external->cidr6 as $url) { foreach ($this->external->cidr6 as $url) {
// todo IP6Helper::minimizeSubnets
$this->cidr6 = SiteFactory::normalize( $this->cidr6 = SiteFactory::normalize(
array_merge($this->cidr6, explode("\n", file_get_contents($url))), array_merge($this->cidr6, explode("\n", file_get_contents($url))),
true true

View File

@@ -3,10 +3,12 @@
namespace OpenCCK\Domain\Factory; namespace OpenCCK\Domain\Factory;
use OpenCCK\Domain\Entity\Site; use OpenCCK\Domain\Entity\Site;
use OpenCCK\Domain\Helper\IP4Helper;
use OpenCCK\Domain\Helper\IP6Helper;
use OpenCCK\Infrastructure\API\App; use OpenCCK\Infrastructure\API\App;
use stdClass; use stdClass;
use function \OpenCCK\getEnv; use function OpenCCK\getEnv;
class SiteFactory { class SiteFactory {
// prettier-ignore // prettier-ignore
@@ -78,8 +80,8 @@ class SiteFactory {
$domains = self::normalize($domains); $domains = self::normalize($domains);
$ip4 = self::normalize($ip4, true); $ip4 = self::normalize($ip4, true);
$ip6 = self::normalize($ip6, true); $ip6 = self::normalize($ip6, true);
$cidr4 = self::normalize($cidr4, true); $cidr4 = IP4Helper::minimizeSubnets(self::normalize($cidr4, true));
$cidr6 = self::normalize($cidr6, 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); 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)) { if (CIDRStorage::getInstance()->has($ip)) {
$searchArray = CIDRStorage::getInstance()->get($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), [ App::getLogger()->debug($ip . ' -> ' . json_encode($searchArray), [
$i + 1 . '/' . $count, $i + 1 . '/' . $count,
@@ -72,8 +72,12 @@ class IP4Helper {
explode(' ', strtr($search, ' ', '')), explode(' ', strtr($search, ' ', '')),
fn(string $cidr) => strlen($cidr) > 0 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); 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']); App::getLogger()->debug($ip . ' -> ' . json_encode($searchArray), [$i + 1 . '/' . $count, 'found']);
} else { } else {
@@ -135,12 +139,19 @@ class IP4Helper {
return $result; return $result;
} }
public static function isInRange(string $ip, array $cidrs): bool { public static function isInCIDR(string $ip, string $cidr): bool {
foreach ($cidrs as $cidr) {
[$subnet, $mask] = explode('/', $cidr); [$subnet, $mask] = explode('/', $cidr);
if ((ip2long($ip) & ~((1 << 32 - $mask) - 1)) === ip2long($subnet)) { if ((ip2long($ip) & ~((1 << 32 - $mask) - 1)) === ip2long($subnet)) {
return true; return true;
} }
return false;
}
public static function isInRange(string $ip, array $cidrs): bool {
foreach ($cidrs as $cidr) {
if (self::isInCIDR($ip, $cidr)) {
return true;
}
} }
return false; return false;
} }

View File

@@ -22,7 +22,7 @@ class IP6Helper {
if (CIDRStorage::getInstance()->has($ip)) { if (CIDRStorage::getInstance()->has($ip)) {
$searchArray = CIDRStorage::getInstance()->get($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), [ App::getLogger()->debug($ip . ' -> ' . json_encode($searchArray), [
$i + 1 . '/' . $count, $i + 1 . '/' . $count,
@@ -72,8 +72,12 @@ class IP6Helper {
explode(' ', strtr($search, ' ', '')), explode(' ', strtr($search, ' ', '')),
fn(string $cidr) => strlen($cidr) > 0 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); 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']); App::getLogger()->debug($ip . ' -> ' . json_encode($searchArray), [$i + 1 . '/' . $count, 'found']);
} else { } else {
@@ -160,10 +164,9 @@ class IP6Helper {
return $result; return $result;
} }
public static function isInRange(string $ip, array $cidrs): bool { public static function isInCidr(string $ip, string $cidr): bool {
$ip = inet_pton($ip); $ip = inet_pton($ip);
foreach ($cidrs as $cidr) {
[$subnet, $mask] = explode('/', $cidr); [$subnet, $mask] = explode('/', $cidr);
$subnet = inet_pton($subnet); $subnet = inet_pton($subnet);
@@ -186,6 +189,15 @@ class IP6Helper {
if (($ip & $mask) === ($subnet & $mask)) { if (($ip & $mask) === ($subnet & $mask)) {
return true; return true;
} }
return false;
}
public static function isInRange(string $ip, array $cidrs): bool {
foreach ($cidrs as $cidr) {
if (self::isInCIDR($ip, $cidr)) {
return true;
}
} }
return false; return false;
} }