Firewall: Automation: Filter - allow TCP/UDP combination in protocol selection, closes https://github.com/opnsense/core/issues/7962

This commit is contained in:
Ad Schellevis 2024-12-18 14:39:19 +01:00
parent 0a408b3d57
commit bcb5bae3e6
4 changed files with 35 additions and 10 deletions

View File

@ -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()
{

View File

@ -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];
}
}

View File

@ -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

View File

@ -57,6 +57,9 @@
<protocol type="ProtocolField">
<Required>Y</Required>
<Default>any</Default>
<AddOptions>
<opt1 value='TCP/UDP'>TCP/UDP</opt1>
</AddOptions>
</protocol>
<!-- XXX: should map internally to 'source' => array('network' => $source_net, "not" => true|false) -->
<source_net type="NetworkAliasField">
@ -148,6 +151,9 @@
<protocol type="ProtocolField">
<Required>Y</Required>
<Default>any</Default>
<AddOptions>
<opt1 value='TCP/UDP'>TCP/UDP</opt1>
</AddOptions>
</protocol>
<source_net type="NetworkAliasField">
<Default>any</Default>