diff --git a/src/opnsense/mvc/app/library/OPNsense/Firewall/Rule.php b/src/opnsense/mvc/app/library/OPNsense/Firewall/Rule.php index 589f27271..9b8c70814 100644 --- a/src/opnsense/mvc/app/library/OPNsense/Firewall/Rule.php +++ b/src/opnsense/mvc/app/library/OPNsense/Firewall/Rule.php @@ -42,7 +42,7 @@ abstract class Rule protected static $aliasMap = []; /* ease the reuse of parsing for pf keywords by using class constants */ - const PARSE_PROTO = 'parseReplaceSimple,tcp/udp:{tcp udp}|a/n:"a/n",proto '; + const PARSE_PROTO = 'parseReplaceSimple,tcp/udp:{tcp udp}|TCP/UDP:{tcp udp}|a/n:"a/n",proto '; protected function loadAliasMap() { diff --git a/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/ProtocolField.php b/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/ProtocolField.php index 318984251..c375fce99 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/ProtocolField.php +++ b/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/ProtocolField.php @@ -34,10 +34,23 @@ namespace OPNsense\Base\FieldTypes; */ class ProtocolField extends BaseListField { + private $additionalOptions = []; + /** * @var array cached collected protocols */ - private static $internalStaticOptionList = array(); + private static $internalStaticOptionList = []; + + /** + * setter for maximum value + * @param integer $value + */ + public function setAddOptions($value) + { + if (is_array($value)) { + $this->additionalOptions = $value; + } + } /** * generate validation data (list of protocols) @@ -46,20 +59,26 @@ class ProtocolField extends BaseListField { /* IPv6 extension headers are skipped by the packet filter, we cannot police them */ $ipv6_ext = array('IPV6-ROUTE', 'IPV6-FRAG', 'IPV6-OPTS', 'IPV6-NONXT', 'MOBILITY-HEADER'); - if (empty(self::$internalStaticOptionList)) { - self::$internalStaticOptionList = array('any' => gettext('any')); + $opt_hash = empty($this->additionalOptions) ? hash('sha256', json_encode($this->additionalOptions)) : '-'; + if (empty(self::$internalStaticOptionList[$opt_hash])) { + self::$internalStaticOptionList[$opt_hash] = ['any' => gettext('any')]; foreach (explode("\n", file_get_contents('/etc/protocols')) as $line) { if (substr($line, 0, 1) != "#") { $parts = preg_split('/\s+/', $line); if (count($parts) >= 4 && $parts[1] > 0) { $protocol = trim(strtoupper($parts[0])); if (!in_array($protocol, $ipv6_ext) && !isset(self::$internalStaticOptionList[$protocol])) { - self::$internalStaticOptionList[$protocol] = $protocol; + self::$internalStaticOptionList[$opt_hash][$protocol] = $protocol; } } } } + /* append additional options */ + foreach ($this->additionalOptions as $prop => $value) { + self::$internalStaticOptionList[$opt_hash][$prop] = $value; + } + asort(self::$internalStaticOptionList[$opt_hash], SORT_NATURAL | SORT_FLAG_CASE); } - $this->internalOptionList = self::$internalStaticOptionList; + $this->internalOptionList = self::$internalStaticOptionList[$opt_hash]; } } diff --git a/src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.php b/src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.php index b401ee182..3d8d40b1f 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.php +++ b/src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.php @@ -41,20 +41,20 @@ class Filter extends BaseModel public function performValidation($validateFullModel = false) { $config = Config::getInstance()->object(); - + $port_protos = ['TCP', 'UDP', 'TCP/UDP']; // standard model validations $messages = parent::performValidation($validateFullModel); foreach ([$this->rules->rule, $this->snatrules->rule] as $rules) { foreach ($rules->iterateItems() as $rule) { if ($validateFullModel || $rule->isFieldChanged()) { // port / protocol validation - if (!empty((string)$rule->source_port) && !in_array($rule->protocol, ['TCP', 'UDP'])) { + if (!empty((string)$rule->source_port) && !in_array($rule->protocol, $port_protos)) { $messages->appendMessage(new Message( gettext("Source ports are only valid for tcp or udp type rules."), $rule->source_port->__reference )); } - if (!empty((string)$rule->destination_port) && !in_array($rule->protocol, ['TCP', 'UDP'])) { + if (!empty((string)$rule->destination_port) && !in_array($rule->protocol, $port_protos)) { $messages->appendMessage(new Message( gettext("Destination ports are only valid for tcp or udp type rules."), $rule->destination_port->__reference @@ -100,7 +100,7 @@ class Filter extends BaseModel $rule->target->__reference )); } - if (!empty((string)$rule->target_port) && !in_array($rule->protocol, ['TCP', 'UDP'])) { + if (!empty((string)$rule->target_port) && !in_array($rule->protocol, $port_protos)) { $messages->appendMessage(new Message( gettext("Target ports are only valid for tcp or udp type rules."), $rule->target_port->__reference diff --git a/src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.xml b/src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.xml index d69b02b42..792fc0579 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.xml +++ b/src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.xml @@ -57,6 +57,9 @@ Y any + + TCP/UDP + @@ -148,6 +151,9 @@ Y any + + TCP/UDP + any