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