diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-14 13:17:47 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-14 13:17:47 +0000 |
commit | 5419d4428c86c488a43124f85e5407d7cbae6541 (patch) | |
tree | 772c4221a20fd7d1b3e7e67c6e21755a50e80fd7 /library/Director/Filter | |
parent | Adding upstream version 1.10.2. (diff) | |
download | icingaweb2-module-director-upstream.tar.xz icingaweb2-module-director-upstream.zip |
Adding upstream version 1.11.1.upstream/1.11.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | library/Director/Filter/CidrExpression.php | 89 | ||||
-rw-r--r-- | library/Director/Filter/FilterEnrichment.php | 29 |
2 files changed, 118 insertions, 0 deletions
diff --git a/library/Director/Filter/CidrExpression.php b/library/Director/Filter/CidrExpression.php new file mode 100644 index 0000000..169ddce --- /dev/null +++ b/library/Director/Filter/CidrExpression.php @@ -0,0 +1,89 @@ +<?php + +namespace Icinga\Module\Director\Filter; + +use Icinga\Data\Filter\FilterExpression; +use InvalidArgumentException; + +use function array_map; +use function filter_var; +use function inet_pton; +use function pack; +use function preg_match; +use function str_pad; +use function str_split; + +class CidrExpression extends FilterExpression +{ + protected $networkAddress; + protected $broadcastAddress; + + public function __construct($column, $sign, $expression) + { + if ($parts = static::splitOptionalCidrString($expression)) { + list($this->networkAddress, $this->broadcastAddress) = $parts; + } else { + throw new InvalidArgumentException("'$expression' isn't valid CIDR notation"); + } + + parent::__construct($column, $sign, $expression); + } + + public static function isCidrFormat(string $string): bool + { + return static::splitOptionalCidrString($string) !== null; + } + + protected static function splitOptionalCidrString(string $string): ?array + { + if (preg_match('#^(.+?)/(\d{1,3})$#', $string, $match)) { + $address = $match[1]; + $mask = (int) $match[2]; + + if (filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) && $mask <= 32) { + $bits = 32; + } elseif (filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) && $mask <= 128) { + $bits = 128; + } else { + return null; + } + + $binaryAddress = inet_pton($address); + $broadcast = $binaryAddress | static::bitmaskToInverseBinaryMask($mask, $bits); + + return [$binaryAddress, $broadcast]; + } + + return null; + } + + public function matches($row): bool + { + if (! isset($row->{$this->column})) { + return false; + } + $value = inet_pton((string) $row->{$this->column}); + + return $value >= $this->networkAddress && $value <= $this->broadcastAddress; + } + + public static function fromExpression(FilterExpression $filter): CidrExpression + { + $sign = $filter->getSign(); + if ($sign !== '=') { + throw new InvalidArgumentException("'$sign' cannot be applied to CIDR notation"); + } + return new CidrExpression($filter->getColumn(), $sign, $filter->getExpression()); + } + + protected static function bitmaskToInverseBinaryMask($mask, $maxLen): string + { + $binary = str_pad(str_pad('', $mask, '0'), $maxLen, '1'); + $address = ''; + foreach (array_map('bindec', str_split($binary, 8)) as $char) { + $address .= pack('C*', $char); + } + + return $address; + } +} diff --git a/library/Director/Filter/FilterEnrichment.php b/library/Director/Filter/FilterEnrichment.php new file mode 100644 index 0000000..c726f76 --- /dev/null +++ b/library/Director/Filter/FilterEnrichment.php @@ -0,0 +1,29 @@ +<?php + +namespace Icinga\Module\Director\Filter; + +use Icinga\Data\Filter\Filter; +use Icinga\Data\Filter\FilterChain; +use Icinga\Data\Filter\FilterExpression; + +class FilterEnrichment +{ + public static function enrichFilter(Filter $filter): Filter + { + if ($filter instanceof FilterExpression) { + if (CidrExpression::isCidrFormat($filter->getExpression())) { + return CidrExpression::fromExpression($filter); + } + } elseif ($filter instanceof FilterChain) { + foreach ($filter->filters() as $subFilter) { + if ($subFilter instanceof FilterExpression + && CidrExpression::isCidrFormat($subFilter->getExpression()) + ) { + $filter->replaceById($subFilter->getId(), CidrExpression::fromExpression($subFilter)); + } + } + } + + return $filter; + } +} |