Firewall/alias, fix validations using our new CallbackValidator type, for https://github.com/opnsense/core/issues/1858

This commit is contained in:
Ad Schellevis 2018-07-10 18:01:37 +02:00
parent 970140aa36
commit fada28880b
2 changed files with 57 additions and 87 deletions

View File

@ -29,9 +29,9 @@
namespace OPNsense\Firewall\FieldTypes;
use OPNsense\Base\FieldTypes\BaseField;
use OPNsense\Base\Validators\CallbackValidator;
use Phalcon\Validation\Validator\Regex;
use Phalcon\Validation\Validator\ExclusionIn;
use Phalcon\Validation\Validator\Callback;
use Phalcon\Validation\Message;
use OPNsense\Firewall\Util;
@ -51,6 +51,11 @@ class AliasContentField extends BaseField
*/
protected $internalValidationMessage = "alias name required";
/**
* @var array list of known countries
*/
private static $internalCountryCodes = array();
/**
* item separator
* @var string
@ -79,12 +84,8 @@ class AliasContentField extends BaseField
*/
private function getItems($data)
{
foreach ($data as $key => $value) {
if (substr($key, strlen($key) - strlen(".content")) == ".content") {
foreach (explode($this->separatorchar, $value) as $value) {
yield $value;
}
}
foreach (explode($this->separatorchar, $data) as $value) {
yield $value;
}
}
@ -94,14 +95,15 @@ class AliasContentField extends BaseField
*/
private function getCountryCodes()
{
$result = array();
foreach (explode("\n", file_get_contents('/usr/local/opnsense/contrib/tzdata/iso3166.tab')) as $line) {
$line = trim($line);
if (strlen($line) > 3 && substr($line, 0, 1) != '#') {
$result[] = substr($line, 0, 2);
if (empty(self::$internalCountryCodes)) {
foreach (explode("\n", file_get_contents('/usr/local/opnsense/contrib/tzdata/iso3166.tab')) as $line) {
$line = trim($line);
if (strlen($line) > 3 && substr($line, 0, 1) != '#') {
self::$internalCountryCodes[] = substr($line, 0, 2);
}
}
}
return $result;
return self::$internalCountryCodes;
}
/**
@ -111,21 +113,15 @@ class AliasContentField extends BaseField
*/
private function validatePort($data)
{
$message = array();
$messages = array();
foreach ($this->getItems($data) as $port) {
if (!Util::isAlias($port) && !Util::isPort($port, true)) {
$message[] = $port;
$messages[] = sprintf(
gettext('Entry "%s" is not a valid port number.'), $port
);
}
}
if (!empty($message)) {
// When validation fails use a callback to return the message so we can add the failed items
return new Callback([
"message" =>sprintf(gettext('Entry "%s" is not a valid port number.'), implode("|", $message)),
"callback" => function () {
return false;
}]);
}
return true;
return $messages;
}
/**
@ -135,25 +131,15 @@ class AliasContentField extends BaseField
*/
private function validateHost($data)
{
$message = array();
$messages = array();
foreach ($this->getItems($data) as $host) {
if (!Util::isAlias($host) && !Util::isIpAddress($host) && !Util::isDomain($host)) {
$message[] = $host;
$messages[] = sprintf(
gettext('Entry "%s" is not a valid hostname or IP address.'), $host
);
}
}
if (!empty($message)) {
// When validation fails use a callback to return the message so we can add the failed items
return new Callback([
"message" =>sprintf(
gettext('Entry "%s" is not a valid hostname or IP address.'),
implode("|", $message)
),
"callback" => function () {
return false;
}]);
}
return true;
return $messages;
}
/**
@ -163,24 +149,25 @@ class AliasContentField extends BaseField
*/
private function validateNetwork($data)
{
$message = array();
$messages = array();
foreach ($this->getItems($data) as $network) {
if (!Util::isAlias($network) && !Util::isIpAddress($network) && !Util::isSubnet($network)) {
$message[] = $network;
$ipaddr_count = 0;
$domain_alias_count = 0;
foreach (explode('-', $network) as $tmpaddr) {
if (Util::isIpAddress($tmpaddr)) {
$ipaddr_count++;
} elseif (trim($tmpaddr) != "") {
$domain_alias_count++;
}
}
if (!Util::isAlias($network) && !Util::isIpAddress($network) && !Util::isSubnet($network) &&
!($ipaddr_count == 2 && $domain_alias_count == 0)) {
$messages[] = sprintf(
gettext('Entry "%s" is not a valid hostname or IP address.'), $network
);
}
}
if (!empty($message)) {
// When validation fails use a callback to return the message so we can add the failed items
return new Callback([
"message" =>sprintf(
gettext('Entry "%s" is not a valid network or IP address.'),
implode("|", $message)
),
"callback" => function () {
return false;
}]);
}
return true;
return $messages;
}
/**
@ -191,24 +178,13 @@ class AliasContentField extends BaseField
private function validateCountry($data)
{
$country_codes = $this->getCountryCodes();
$message = array();
$messages = array();
foreach ($this->getItems($data) as $country) {
if (!in_array($country, $country_codes)) {
$message[] = $country;
$messages[] = sprintf(gettext('Entry "%s" is not a valid country code.'), $country);
}
}
if (!empty($message)) {
// When validation fails use a callback to return the message so we can add the failed items
return new Callback([
"message" =>sprintf(
gettext('Entry "%s" is not a valid country code.'),
implode("|", $message)
),
"callback" => function () {
return false;
}]);
}
return true;
return $messages;
}
/**
@ -219,29 +195,27 @@ class AliasContentField extends BaseField
{
$validators = parent::getValidators();
if ($this->internalValue != null) {
$alias_type = (string)$this->getParentNode()->type;
switch ($alias_type) {
switch ((string)$this->getParentNode()->type) {
case "port":
$validators[] = new Callback(["callback" => function ($data) {
$validators[] = new CallbackValidator(["callback" => function ($data) {
return $this->validatePort($data);
}
]);
break;
case "host":
$validators[] = new Callback(["callback" => function ($data) {
$validators[] = new CallbackValidator(["callback" => function ($data) {
return $this->validateHost($data);
}
]);
break;
case "geoip":
$validators[] = new Callback(["callback" => function ($data) {
$validators[] = new CallbackValidator(["callback" => function ($data) {
return $this->validateCountry($data);
}
]);
break;
case "network":
$validators[] = new Callback(["callback" => function ($data) {
$validators[] = new CallbackValidator(["callback" => function ($data) {
return $this->validateNetwork($data);
}
]);

View File

@ -29,9 +29,10 @@
namespace OPNsense\Firewall\FieldTypes;
use OPNsense\Base\FieldTypes\BaseField;
use OPNsense\Base\Validators\CallbackValidator;
use Phalcon\Validation\Validator\Regex;
use Phalcon\Validation\Validator\ExclusionIn;
use Phalcon\Validation\Validator\Callback;
/**
* Class AliasNameField
@ -72,19 +73,14 @@ class AliasNameField extends BaseField
'The name must be less than 32 characters long and may only consist of the following characters: %s'
), 'a-z, A-Z, 0-9, _'),
'pattern'=>'/[_0-9a-zA-z]{1,32}/'));
$validators[] = new Callback(
$validators[] = new CallbackValidator(
[
"message" => gettext('Reserved protocol or service names may not be used'),
"callback" => function ($data) {
foreach ($data as $key => $value) {
if (substr($key, strlen($key) - strlen(".name")) == ".name") {
if (getservbyname($value, 'tcp') ||
getservbyname($value, 'udp') || getprotobyname($value)) {
return false;
}
}
"callback" => function ($value) {
if (getservbyname($value, 'tcp') ||
getservbyname($value, 'udp') || getprotobyname($value)) {
return array(gettext('Reserved protocol or service names may not be used'));
}
return true;
return array();
}
]
);