diff --git a/src/opnsense/mvc/app/library/OPNsense/Firewall/Util.php b/src/opnsense/mvc/app/library/OPNsense/Firewall/Util.php index 819e52e9c..446f2caba 100644 --- a/src/opnsense/mvc/app/library/OPNsense/Firewall/Util.php +++ b/src/opnsense/mvc/app/library/OPNsense/Firewall/Util.php @@ -94,6 +94,36 @@ class Util return false; } + /** + * is provided network strict (host bits not set) + * @param string $network network + * @return boolean + */ + public static function isStrict($network) + { + if (self::isSubnet($network)) { + list($net, $mask) = explode('/', $network); + $ip_net = inet_pton($net); + $bits = (strpos($net, ":") !== false && $mask <= 128) ? 128 : 32; + + $ip_mask = ""; + $significant_bits = $mask; + for ($i = 0; $i < $bits/8; $i++) { + if ($significant_bits >= 8) { + $ip_mask .= chr(0xFF); + $significant_bits -= 8; + } else { + $ip_mask .= chr(~(0xFF >> $significant_bits)); + $significant_bits = 0; + } + } + + return $ip_net == ($ip_net & $ip_mask); + } + + return false; + } + /** * is provided network a valid wildcard (https://en.wikipedia.org/wiki/Wildcard_mask) * @param string $network network diff --git a/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/NetworkField.php b/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/NetworkField.php index 08f77322a..f5defde42 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/NetworkField.php +++ b/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/NetworkField.php @@ -75,6 +75,11 @@ class NetworkField extends BaseField */ private $internalAsList = false; + /** + * @var bool when set, host bits with a value other than zero are not allowed in the notation if a mask is provided + */ + private $internalStrict = false; + /** * always lowercase / trim networks * @param string $value @@ -150,6 +155,19 @@ class NetworkField extends BaseField } } + /** + * select if host bits are allowed in the notation + * @param $value + */ + public function setStrict($value) + { + if (trim(strtoupper($value)) == "Y") { + $this->internalStrict = true; + } else { + $this->internalStrict = false; + } + } + /** * get valid options, descriptions and selected value * @return array @@ -184,7 +202,8 @@ class NetworkField extends BaseField 'split' => $this->internalFieldSeparator, 'netMaskRequired' => $this->internalNetMaskRequired, 'netMaskAllowed' => $this->internalNetMaskAllowed, - 'version' => $this->internalAddressFamily + 'version' => $this->internalAddressFamily, + 'strict' => $this->internalStrict )); } } diff --git a/src/opnsense/mvc/app/models/OPNsense/Base/Validators/NetworkValidator.php b/src/opnsense/mvc/app/models/OPNsense/Base/Validators/NetworkValidator.php index 1215aa9bc..26a9eefc7 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Base/Validators/NetworkValidator.php +++ b/src/opnsense/mvc/app/models/OPNsense/Base/Validators/NetworkValidator.php @@ -31,6 +31,7 @@ namespace OPNsense\Base\Validators; use OPNsense\Base\BaseValidator; +use OPNsense\Firewall\Util; use Phalcon\Messages\Message; /** @@ -46,7 +47,7 @@ class NetworkValidator extends BaseValidator * noPrivate : true, false (default) * noSubnet : true, false (default) * netMaskRequired : true, false (default) - * + * strict: : true, false (default) * * @param $validator * @param string $attribute @@ -89,6 +90,7 @@ class NetworkValidator extends BaseValidator if ($this->getOption('netMaskAllowed') === false) { $result = false; } else { + $cidr = $value; $parts = explode("/", $value); if (count($parts) > 2 || !ctype_digit($parts[1])) { // more parts then expected or second part is not numeric @@ -108,6 +110,10 @@ class NetworkValidator extends BaseValidator } } } + + if ($this->getOption('strict') === true && !Util::isStrict($cidr)) { + $result = false; + } } } elseif ($this->getOption('netMaskRequired') === true) { $result = false;