feat(fw): add ReloadPolicy option in firewalld.conf
Resolves: RHEL-5978
This commit is contained in:
parent
09e9b4b7ca
commit
9c0f94b6e4
@ -0,0 +1,66 @@
|
|||||||
|
From 11ee9b9ed8da78bfc11edffc2c9386efa41be1cf Mon Sep 17 00:00:00 2001
|
||||||
|
From: Eric Garver <eric@garver.life>
|
||||||
|
Date: Mon, 18 Dec 2023 18:22:38 -0500
|
||||||
|
Subject: [PATCH 08/22] v2.1.0: improvement(nftables): do not track rule
|
||||||
|
handles for policy table
|
||||||
|
|
||||||
|
It's not necessary. This table is transient and we simply delete the
|
||||||
|
entire table when we're done with it.
|
||||||
|
|
||||||
|
(cherry picked from commit 119dff1d86f841cd2f33ddbab278bc9257dae7b0)
|
||||||
|
---
|
||||||
|
src/firewall/core/nftables.py | 24 +++++++-----------------
|
||||||
|
1 file changed, 7 insertions(+), 17 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/firewall/core/nftables.py b/src/firewall/core/nftables.py
|
||||||
|
index 3df3fa3c3742..690a5dc067ab 100644
|
||||||
|
--- a/src/firewall/core/nftables.py
|
||||||
|
+++ b/src/firewall/core/nftables.py
|
||||||
|
@@ -386,6 +386,11 @@ class nftables(object):
|
||||||
|
if verb not in output["nftables"][index]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
+ # don't bother tracking handles for the policy table as we simply
|
||||||
|
+ # delete the entire table.
|
||||||
|
+ if TABLE_NAME_POLICY == output["nftables"][index][verb]["rule"]["table"]:
|
||||||
|
+ continue
|
||||||
|
+
|
||||||
|
self.rule_to_handle[rule_key] = output["nftables"][index][verb]["rule"]["handle"]
|
||||||
|
|
||||||
|
def set_rule(self, rule, log_denied):
|
||||||
|
@@ -408,18 +413,8 @@ class nftables(object):
|
||||||
|
"name": table}}}]
|
||||||
|
|
||||||
|
def build_flush_rules(self):
|
||||||
|
- # Policy is stashed in a separate table that we're _not_ going to
|
||||||
|
- # flush. As such, we retain the policy rule handles and ref counts.
|
||||||
|
- saved_rule_to_handle = {}
|
||||||
|
- saved_rule_ref_count = {}
|
||||||
|
- for rule in self._build_set_policy_rules_ct_rules(True):
|
||||||
|
- policy_key = self._get_rule_key(rule)
|
||||||
|
- if policy_key in self.rule_to_handle:
|
||||||
|
- saved_rule_to_handle[policy_key] = self.rule_to_handle[policy_key]
|
||||||
|
- saved_rule_ref_count[policy_key] = self.rule_ref_count[policy_key]
|
||||||
|
-
|
||||||
|
- self.rule_to_handle = saved_rule_to_handle
|
||||||
|
- self.rule_ref_count = saved_rule_ref_count
|
||||||
|
+ self.rule_to_handle = {}
|
||||||
|
+ self.rule_ref_count = {}
|
||||||
|
self.rich_rule_priority_counts = {}
|
||||||
|
self.policy_priority_counts = {}
|
||||||
|
self.zone_source_index_cache = {}
|
||||||
|
@@ -475,11 +470,6 @@ class nftables(object):
|
||||||
|
|
||||||
|
rules += self._build_set_policy_rules_ct_rules(True)
|
||||||
|
elif policy == "ACCEPT":
|
||||||
|
- for rule in self._build_set_policy_rules_ct_rules(False):
|
||||||
|
- policy_key = self._get_rule_key(rule)
|
||||||
|
- if policy_key in self.rule_to_handle:
|
||||||
|
- rules.append(rule)
|
||||||
|
-
|
||||||
|
rules += self._build_delete_table_rules(TABLE_NAME_POLICY)
|
||||||
|
else:
|
||||||
|
raise FirewallError(UNKNOWN_ERROR, "not implemented")
|
||||||
|
--
|
||||||
|
2.43.5
|
||||||
|
|
203
0009-v2.1.0-improvement-fw-make-set_policy-DROP-more-flex.patch
Normal file
203
0009-v2.1.0-improvement-fw-make-set_policy-DROP-more-flex.patch
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
From c53dabcb9ca5c6d9ab2b076d961127a67afe8f8f Mon Sep 17 00:00:00 2001
|
||||||
|
From: Thomas Haller <thaller@redhat.com>
|
||||||
|
Date: Fri, 11 Aug 2023 18:16:20 +0200
|
||||||
|
Subject: [PATCH 09/22] v2.1.0: improvement(fw): make set_policy("DROP") more
|
||||||
|
flexible
|
||||||
|
|
||||||
|
We will add a reload-policy via
|
||||||
|
|
||||||
|
ReloadPolicy=OUTPUT:{ACCEPT,REJECT,DROP},INPUT:{ACCEPT,REJECT,DROP},FORWARD:{ACCEPT,REJECT,DROP}
|
||||||
|
|
||||||
|
Extend set_policy() so that the "DROP" policy can be overridden.
|
||||||
|
|
||||||
|
(cherry picked from commit e3bb468ff469373d193398b471a59f7ab7d29f27)
|
||||||
|
---
|
||||||
|
src/firewall/core/ebtables.py | 2 +-
|
||||||
|
src/firewall/core/fw.py | 27 +++++++++++++---
|
||||||
|
src/firewall/core/ipXtables.py | 11 +++++--
|
||||||
|
src/firewall/core/nftables.py | 56 ++++++++++++++++++++++++----------
|
||||||
|
4 files changed, 72 insertions(+), 24 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/firewall/core/ebtables.py b/src/firewall/core/ebtables.py
|
||||||
|
index c1c0b8587a5c..f059975724a5 100644
|
||||||
|
--- a/src/firewall/core/ebtables.py
|
||||||
|
+++ b/src/firewall/core/ebtables.py
|
||||||
|
@@ -237,7 +237,7 @@ class ebtables(object):
|
||||||
|
rules.append(["-t", table, flag])
|
||||||
|
return rules
|
||||||
|
|
||||||
|
- def build_set_policy_rules(self, policy):
|
||||||
|
+ def build_set_policy_rules(self, policy, policy_details):
|
||||||
|
rules = []
|
||||||
|
_policy = "DROP" if policy == "PANIC" else policy
|
||||||
|
for table in BUILT_IN_CHAINS.keys():
|
||||||
|
diff --git a/src/firewall/core/fw.py b/src/firewall/core/fw.py
|
||||||
|
index f1bc124b9443..ccec875f3c3c 100644
|
||||||
|
--- a/src/firewall/core/fw.py
|
||||||
|
+++ b/src/firewall/core/fw.py
|
||||||
|
@@ -983,7 +983,18 @@ class Firewall(object):
|
||||||
|
if use_transaction is None:
|
||||||
|
transaction.execute(True)
|
||||||
|
|
||||||
|
- def set_policy(self, policy, use_transaction=None):
|
||||||
|
+ def _set_policy_build_rules(self, backend, policy, policy_details=None):
|
||||||
|
+ assert policy in ("ACCEPT", "DROP", "PANIC")
|
||||||
|
+ if policy_details is None:
|
||||||
|
+ dp = "ACCEPT" if policy == "ACCEPT" else "DROP"
|
||||||
|
+ policy_details = {
|
||||||
|
+ "INPUT": dp,
|
||||||
|
+ "OUTPUT": dp,
|
||||||
|
+ "FORWARD": dp,
|
||||||
|
+ }
|
||||||
|
+ return backend.build_set_policy_rules(policy, policy_details)
|
||||||
|
+
|
||||||
|
+ def set_policy(self, policy, policy_details=None, use_transaction=None):
|
||||||
|
if use_transaction is None:
|
||||||
|
transaction = FirewallTransaction(self)
|
||||||
|
else:
|
||||||
|
@@ -992,7 +1003,7 @@ class Firewall(object):
|
||||||
|
log.debug1("Setting policy to '%s'", policy)
|
||||||
|
|
||||||
|
for backend in self.enabled_backends():
|
||||||
|
- rules = backend.build_set_policy_rules(policy)
|
||||||
|
+ rules = self._set_policy_build_rules(backend, policy, policy_details)
|
||||||
|
transaction.add_rules(backend, rules)
|
||||||
|
|
||||||
|
if use_transaction is None:
|
||||||
|
@@ -1224,13 +1235,19 @@ class Firewall(object):
|
||||||
|
# for the old backend that was set to DROP above.
|
||||||
|
if not self._panic and old_firewall_backend != self._firewall_backend:
|
||||||
|
if old_firewall_backend == "nftables":
|
||||||
|
- for rule in self.nftables_backend.build_set_policy_rules("ACCEPT"):
|
||||||
|
+ for rule in self._set_policy_build_rules(
|
||||||
|
+ self.nftables_backend, "ACCEPT"
|
||||||
|
+ ):
|
||||||
|
self.nftables_backend.set_rule(rule, self._log_denied)
|
||||||
|
else:
|
||||||
|
- for rule in self.ip4tables_backend.build_set_policy_rules("ACCEPT"):
|
||||||
|
+ for rule in self._set_policy_build_rules(
|
||||||
|
+ self.ip4tables_backend, "ACCEPT"
|
||||||
|
+ ):
|
||||||
|
self.ip4tables_backend.set_rule(rule, self._log_denied)
|
||||||
|
if self.ip6tables_enabled:
|
||||||
|
- for rule in self.ip6tables_backend.build_set_policy_rules("ACCEPT"):
|
||||||
|
+ for rule in self._set_policy_build_rules(
|
||||||
|
+ self.ip6tables_backend, "ACCEPT"
|
||||||
|
+ ):
|
||||||
|
self.ip6tables_backend.set_rule(rule, self._log_denied)
|
||||||
|
|
||||||
|
if start_exception:
|
||||||
|
diff --git a/src/firewall/core/ipXtables.py b/src/firewall/core/ipXtables.py
|
||||||
|
index e05a2bd4d7ed..1a0cea7a3b4e 100644
|
||||||
|
--- a/src/firewall/core/ipXtables.py
|
||||||
|
+++ b/src/firewall/core/ipXtables.py
|
||||||
|
@@ -578,7 +578,7 @@ class ip4tables(object):
|
||||||
|
rules.append(["-t", table, flag])
|
||||||
|
return rules
|
||||||
|
|
||||||
|
- def build_set_policy_rules(self, policy):
|
||||||
|
+ def build_set_policy_rules(self, policy, policy_details):
|
||||||
|
rules = []
|
||||||
|
_policy = "DROP" if policy == "PANIC" else policy
|
||||||
|
for table in BUILT_IN_CHAINS.keys():
|
||||||
|
@@ -587,7 +587,14 @@ class ip4tables(object):
|
||||||
|
if table == "nat":
|
||||||
|
continue
|
||||||
|
for chain in BUILT_IN_CHAINS[table]:
|
||||||
|
- rules.append(["-t", table, "-P", chain, _policy])
|
||||||
|
+ if table == "filter":
|
||||||
|
+ p = policy_details[chain]
|
||||||
|
+ if p == "REJECT":
|
||||||
|
+ rules.append(["-t", table, "-A", chain, "-j", "REJECT"])
|
||||||
|
+ p = "DROP"
|
||||||
|
+ else:
|
||||||
|
+ p = _policy
|
||||||
|
+ rules.append(["-t", table, "-P", chain, p])
|
||||||
|
return rules
|
||||||
|
|
||||||
|
def supported_icmp_types(self, ipv=None):
|
||||||
|
diff --git a/src/firewall/core/nftables.py b/src/firewall/core/nftables.py
|
||||||
|
index 690a5dc067ab..e9816147ef8e 100644
|
||||||
|
--- a/src/firewall/core/nftables.py
|
||||||
|
+++ b/src/firewall/core/nftables.py
|
||||||
|
@@ -421,20 +421,17 @@ class nftables(object):
|
||||||
|
|
||||||
|
return self._build_delete_table_rules(TABLE_NAME)
|
||||||
|
|
||||||
|
- def _build_set_policy_rules_ct_rules(self, enable):
|
||||||
|
+ def _build_set_policy_rules_ct_rule(self, enable, hook):
|
||||||
|
add_del = { True: "add", False: "delete" }[enable]
|
||||||
|
- rules = []
|
||||||
|
- for hook in ["input", "forward", "output"]:
|
||||||
|
- rules.append({add_del: {"rule": {"family": "inet",
|
||||||
|
- "table": TABLE_NAME_POLICY,
|
||||||
|
- "chain": "%s_%s" % ("filter", hook),
|
||||||
|
- "expr": [{"match": {"left": {"ct": {"key": "state"}},
|
||||||
|
- "op": "in",
|
||||||
|
- "right": {"set": ["established", "related"]}}},
|
||||||
|
- {"accept": None}]}}})
|
||||||
|
- return rules
|
||||||
|
-
|
||||||
|
- def build_set_policy_rules(self, policy):
|
||||||
|
+ return {add_del: {"rule": {"family": "inet",
|
||||||
|
+ "table": TABLE_NAME_POLICY,
|
||||||
|
+ "chain": "%s_%s" % ("filter", hook),
|
||||||
|
+ "expr": [{"match": {"left": {"ct": {"key": "state"}},
|
||||||
|
+ "op": "in",
|
||||||
|
+ "right": {"set": ["established", "related"]}}},
|
||||||
|
+ {"accept": None}]}}}
|
||||||
|
+
|
||||||
|
+ def build_set_policy_rules(self, policy, policy_details):
|
||||||
|
# Policy is not exposed to the user. It's only to make sure we DROP
|
||||||
|
# packets while reloading and for panic mode. As such, using hooks with
|
||||||
|
# a higher priority than our base chains is sufficient.
|
||||||
|
@@ -459,16 +456,43 @@ class nftables(object):
|
||||||
|
|
||||||
|
# To drop everything except existing connections we use
|
||||||
|
# "filter" because it occurs _after_ conntrack.
|
||||||
|
- for hook in ["input", "forward", "output"]:
|
||||||
|
+ for hook in ("INPUT", "FORWARD", "OUTPUT"):
|
||||||
|
+ d_policy = policy_details[hook]
|
||||||
|
+ assert d_policy in ("ACCEPT", "REJECT", "DROP")
|
||||||
|
+ hook = hook.lower()
|
||||||
|
+ chain_name = f"filter_{hook}"
|
||||||
|
+
|
||||||
|
rules.append({"add": {"chain": {"family": "inet",
|
||||||
|
"table": TABLE_NAME_POLICY,
|
||||||
|
- "name": "%s_%s" % ("filter", hook),
|
||||||
|
+ "name": chain_name,
|
||||||
|
"type": "filter",
|
||||||
|
"hook": hook,
|
||||||
|
"prio": 0 + NFT_HOOK_OFFSET - 1,
|
||||||
|
"policy": "drop"}}})
|
||||||
|
|
||||||
|
- rules += self._build_set_policy_rules_ct_rules(True)
|
||||||
|
+ rules.append(self._build_set_policy_rules_ct_rule(True, hook))
|
||||||
|
+
|
||||||
|
+ if d_policy == "ACCEPT":
|
||||||
|
+ expr_fragment = {"accept": None}
|
||||||
|
+ elif d_policy == "DROP":
|
||||||
|
+ expr_fragment = {"drop": None}
|
||||||
|
+ else:
|
||||||
|
+ expr_fragment = {
|
||||||
|
+ "reject": {"type": "icmpx", "expr": "admin-prohibited"}
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ rules.append(
|
||||||
|
+ {
|
||||||
|
+ "add": {
|
||||||
|
+ "rule": {
|
||||||
|
+ "family": "inet",
|
||||||
|
+ "table": TABLE_NAME_POLICY,
|
||||||
|
+ "chain": chain_name,
|
||||||
|
+ "expr": [expr_fragment],
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ )
|
||||||
|
elif policy == "ACCEPT":
|
||||||
|
rules += self._build_delete_table_rules(TABLE_NAME_POLICY)
|
||||||
|
else:
|
||||||
|
--
|
||||||
|
2.43.5
|
||||||
|
|
303
0010-v2.1.0-feat-fw-add-ReloadPolicy-option-in-firewalld..patch
Normal file
303
0010-v2.1.0-feat-fw-add-ReloadPolicy-option-in-firewalld..patch
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
From 67c8a0010ba6244c40e48a93560eb66d91a2ca09 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Thomas Haller <thaller@redhat.com>
|
||||||
|
Date: Mon, 14 Aug 2023 14:53:55 +0200
|
||||||
|
Subject: [PATCH 10/22] v2.1.0: feat(fw): add ReloadPolicy option in
|
||||||
|
firewalld.conf
|
||||||
|
|
||||||
|
One interesting aspect is that during `firewall-cmd --reload`, the code
|
||||||
|
first sets the policy to "DROP", before reloading "firewalld.conf". That
|
||||||
|
means, changing the value only takes effect after the next reload. But
|
||||||
|
that seems expected as we set the policy before starting to reload.
|
||||||
|
|
||||||
|
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2149039
|
||||||
|
(cherry picked from commit 0019371a8f42d376ac9cce79cc5e1e7d2049f021)
|
||||||
|
---
|
||||||
|
config/firewalld.conf | 8 +++
|
||||||
|
doc/xml/firewalld.conf.xml | 16 ++++++
|
||||||
|
src/firewall/config/__init__.py.in | 1 +
|
||||||
|
src/firewall/core/fw.py | 13 ++++-
|
||||||
|
src/firewall/core/io/firewalld_conf.py | 56 ++++++++++++++++++++-
|
||||||
|
src/tests/features/features.at | 1 +
|
||||||
|
src/tests/features/reloadpolicy.at | 12 +++++
|
||||||
|
src/tests/unit/test_firewalld_conf.py | 68 ++++++++++++++++++++++++++
|
||||||
|
8 files changed, 172 insertions(+), 3 deletions(-)
|
||||||
|
create mode 100644 src/tests/features/reloadpolicy.at
|
||||||
|
create mode 100644 src/tests/unit/test_firewalld_conf.py
|
||||||
|
|
||||||
|
diff --git a/config/firewalld.conf b/config/firewalld.conf
|
||||||
|
index f8caf11c8a86..7a0be1ff1b76 100644
|
||||||
|
--- a/config/firewalld.conf
|
||||||
|
+++ b/config/firewalld.conf
|
||||||
|
@@ -66,6 +66,14 @@ FirewallBackend=nftables
|
||||||
|
# Default: yes
|
||||||
|
FlushAllOnReload=yes
|
||||||
|
|
||||||
|
+# ReloadPolicy
|
||||||
|
+# Policy during reload. By default all traffic except for established
|
||||||
|
+# connections is dropped while the rules are updated. Set to "DROP", "REJECT"
|
||||||
|
+# or "ACCEPT". Alternatively, specify it per table, like
|
||||||
|
+# "OUTPUT:ACCEPT,INPUT:DROP,FORWARD:REJECT".
|
||||||
|
+# Default: ReloadPolicy=INPUT:DROP,FORWARD:DROP,OUTPUT:DROP
|
||||||
|
+ReloadPolicy=INPUT:DROP,FORWARD:DROP,OUTPUT:DROP
|
||||||
|
+
|
||||||
|
# RFC3964_IPv4
|
||||||
|
# As per RFC 3964, filter IPv6 traffic with 6to4 destination addresses that
|
||||||
|
# correspond to IPv4 addresses that should not be routed over the public
|
||||||
|
diff --git a/doc/xml/firewalld.conf.xml b/doc/xml/firewalld.conf.xml
|
||||||
|
index e4312acc8e1c..022569ccf502 100644
|
||||||
|
--- a/doc/xml/firewalld.conf.xml
|
||||||
|
+++ b/doc/xml/firewalld.conf.xml
|
||||||
|
@@ -195,6 +195,22 @@
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
+ <varlistentry>
|
||||||
|
+ <term><option>ReloadPolicy</option></term>
|
||||||
|
+ <listitem>
|
||||||
|
+ <para>
|
||||||
|
+ The policy during reload. By default, all traffic except
|
||||||
|
+ established connections is dropped while reloading the
|
||||||
|
+ firewall rules. This can be overridden for INPUT, FORWARD
|
||||||
|
+ and OUTPUT. The accepted values are "DROP", "REJECT" and
|
||||||
|
+ "ACCEPT", which then applies to all tables. Alternatively,
|
||||||
|
+ the policy can be specified per table, like
|
||||||
|
+ "INPUT:REJECT,FORWARD:DROP,OUTPUT:ACCEPT".
|
||||||
|
+ Defaults to "INPUT:DROP,FORWARD:DROP,OUTPUT:DROP".
|
||||||
|
+ </para>
|
||||||
|
+ </listitem>
|
||||||
|
+ </varlistentry>
|
||||||
|
+
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>RFC3964_IPv4</option></term>
|
||||||
|
<listitem>
|
||||||
|
diff --git a/src/firewall/config/__init__.py.in b/src/firewall/config/__init__.py.in
|
||||||
|
index d982384a0382..da1e31e10e58 100644
|
||||||
|
--- a/src/firewall/config/__init__.py.in
|
||||||
|
+++ b/src/firewall/config/__init__.py.in
|
||||||
|
@@ -133,5 +133,6 @@ FALLBACK_LOG_DENIED = "off"
|
||||||
|
FALLBACK_AUTOMATIC_HELPERS = "no"
|
||||||
|
FALLBACK_FIREWALL_BACKEND = "nftables"
|
||||||
|
FALLBACK_FLUSH_ALL_ON_RELOAD = True
|
||||||
|
+FALLBACK_RELOAD_POLICY = "INPUT:DROP,FORWARD:DROP,OUTPUT:DROP"
|
||||||
|
FALLBACK_RFC3964_IPV4 = True
|
||||||
|
FALLBACK_ALLOW_ZONE_DRIFTING = False
|
||||||
|
diff --git a/src/firewall/core/fw.py b/src/firewall/core/fw.py
|
||||||
|
index ccec875f3c3c..ac13be122b66 100644
|
||||||
|
--- a/src/firewall/core/fw.py
|
||||||
|
+++ b/src/firewall/core/fw.py
|
||||||
|
@@ -1000,7 +1000,13 @@ class Firewall(object):
|
||||||
|
else:
|
||||||
|
transaction = use_transaction
|
||||||
|
|
||||||
|
- log.debug1("Setting policy to '%s'", policy)
|
||||||
|
+ log.debug1(
|
||||||
|
+ "Setting policy to '%s'%s",
|
||||||
|
+ policy,
|
||||||
|
+ f" (ReloadPolicy={firewalld_conf._unparse_reload_policy(policy_details)})"
|
||||||
|
+ if policy == "DROP"
|
||||||
|
+ else "",
|
||||||
|
+ )
|
||||||
|
|
||||||
|
for backend in self.enabled_backends():
|
||||||
|
rules = self._set_policy_build_rules(backend, policy, policy_details)
|
||||||
|
@@ -1146,7 +1152,10 @@ class Firewall(object):
|
||||||
|
_ipset_objs.append(self.ipset.get_ipset(_name))
|
||||||
|
|
||||||
|
if not _panic:
|
||||||
|
- self.set_policy("DROP")
|
||||||
|
+ reload_policy = firewalld_conf._parse_reload_policy(
|
||||||
|
+ self._firewalld_conf.get("ReloadPolicy")
|
||||||
|
+ )
|
||||||
|
+ self.set_policy("DROP", policy_details=reload_policy)
|
||||||
|
|
||||||
|
self.flush()
|
||||||
|
self.cleanup()
|
||||||
|
diff --git a/src/firewall/core/io/firewalld_conf.py b/src/firewall/core/io/firewalld_conf.py
|
||||||
|
index b907c5b1e60b..d2879b319d1f 100644
|
||||||
|
--- a/src/firewall/core/io/firewalld_conf.py
|
||||||
|
+++ b/src/firewall/core/io/firewalld_conf.py
|
||||||
|
@@ -31,7 +31,7 @@ valid_keys = [ "DefaultZone", "MinimalMark", "CleanupOnExit",
|
||||||
|
"CleanupModulesOnExit", "Lockdown", "IPv6_rpfilter",
|
||||||
|
"IndividualCalls", "LogDenied", "AutomaticHelpers",
|
||||||
|
"FirewallBackend", "FlushAllOnReload", "RFC3964_IPv4",
|
||||||
|
- "AllowZoneDrifting" ]
|
||||||
|
+ "AllowZoneDrifting", "ReloadPolicy" ]
|
||||||
|
|
||||||
|
class firewalld_conf(object):
|
||||||
|
def __init__(self, filename):
|
||||||
|
@@ -77,6 +77,7 @@ class firewalld_conf(object):
|
||||||
|
self.set("AutomaticHelpers", config.FALLBACK_AUTOMATIC_HELPERS)
|
||||||
|
self.set("FirewallBackend", config.FALLBACK_FIREWALL_BACKEND)
|
||||||
|
self.set("FlushAllOnReload", "yes" if config.FALLBACK_FLUSH_ALL_ON_RELOAD else "no")
|
||||||
|
+ self.set("ReloadPolicy", config.FALLBACK_RELOAD_POLICY)
|
||||||
|
self.set("RFC3964_IPv4", "yes" if config.FALLBACK_RFC3964_IPV4 else "no")
|
||||||
|
self.set("AllowZoneDrifting", "yes" if config.FALLBACK_ALLOW_ZONE_DRIFTING else "no")
|
||||||
|
|
||||||
|
@@ -208,6 +209,17 @@ class firewalld_conf(object):
|
||||||
|
config.FALLBACK_FLUSH_ALL_ON_RELOAD)
|
||||||
|
self.set("FlushAllOnReload", str(config.FALLBACK_FLUSH_ALL_ON_RELOAD))
|
||||||
|
|
||||||
|
+ value = self.get("ReloadPolicy")
|
||||||
|
+ try:
|
||||||
|
+ value = self._parse_reload_policy(value)
|
||||||
|
+ except ValueError:
|
||||||
|
+ log.warning(
|
||||||
|
+ "ReloadPolicy '%s' is not valid, using default value '%s'",
|
||||||
|
+ value,
|
||||||
|
+ config.FALLBACK_RELOAD_POLICY,
|
||||||
|
+ )
|
||||||
|
+ self.set("ReloadPolicy", config.FALLBACK_RELOAD_POLICY)
|
||||||
|
+
|
||||||
|
value = self.get("RFC3964_IPv4")
|
||||||
|
if not value or value.lower() not in [ "yes", "true", "no", "false" ]:
|
||||||
|
if value is not None:
|
||||||
|
@@ -330,3 +342,45 @@ class firewalld_conf(object):
|
||||||
|
raise IOError("Failed to create '%s': %s" % (self.filename, msg))
|
||||||
|
else:
|
||||||
|
os.chmod(self.filename, 0o600)
|
||||||
|
+
|
||||||
|
+ @staticmethod
|
||||||
|
+ def _parse_reload_policy(value):
|
||||||
|
+ valid = True
|
||||||
|
+ result = {
|
||||||
|
+ "INPUT": "DROP",
|
||||||
|
+ "FORWARD": "DROP",
|
||||||
|
+ "OUTPUT": "DROP",
|
||||||
|
+ }
|
||||||
|
+ if value:
|
||||||
|
+ value = value.strip()
|
||||||
|
+ v = value.upper()
|
||||||
|
+ if v in ("ACCEPT", "REJECT", "DROP"):
|
||||||
|
+ for k in result:
|
||||||
|
+ result[k] = v
|
||||||
|
+ else:
|
||||||
|
+ for a in value.replace(";", ",").split(","):
|
||||||
|
+ a = a.strip()
|
||||||
|
+ if not a:
|
||||||
|
+ continue
|
||||||
|
+ a2 = a.replace("=", ":").split(":", 2)
|
||||||
|
+ if len(a2) != 2:
|
||||||
|
+ valid = False
|
||||||
|
+ continue
|
||||||
|
+ k = a2[0].strip().upper()
|
||||||
|
+ if k not in result:
|
||||||
|
+ valid = False
|
||||||
|
+ continue
|
||||||
|
+ v = a2[1].strip().upper()
|
||||||
|
+ if v not in ("ACCEPT", "REJECT", "DROP"):
|
||||||
|
+ valid = False
|
||||||
|
+ continue
|
||||||
|
+ result[k] = v
|
||||||
|
+
|
||||||
|
+ if not valid:
|
||||||
|
+ raise ValueError("Invalid ReloadPolicy")
|
||||||
|
+
|
||||||
|
+ return result
|
||||||
|
+
|
||||||
|
+ @staticmethod
|
||||||
|
+ def _unparse_reload_policy(value):
|
||||||
|
+ return ",".join(f"{k}:{v}" for k, v in value.items())
|
||||||
|
diff --git a/src/tests/features/features.at b/src/tests/features/features.at
|
||||||
|
index f59baea1cd70..065cb2872e88 100644
|
||||||
|
--- a/src/tests/features/features.at
|
||||||
|
+++ b/src/tests/features/features.at
|
||||||
|
@@ -20,3 +20,4 @@ m4_include([features/startup_failsafe.at])
|
||||||
|
m4_include([features/ipset.at])
|
||||||
|
m4_include([features/reset_defaults.at])
|
||||||
|
m4_include([features/iptables_no_flush_on_shutdown.at])
|
||||||
|
+m4_include([features/reloadpolicy.at])
|
||||||
|
diff --git a/src/tests/features/reloadpolicy.at b/src/tests/features/reloadpolicy.at
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000000..fea1aa26aab4
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/tests/features/reloadpolicy.at
|
||||||
|
@@ -0,0 +1,12 @@
|
||||||
|
+FWD_START_TEST([check ReloadPolicy])
|
||||||
|
+AT_KEYWORDS(reloadpolicy rhbz2149039)
|
||||||
|
+
|
||||||
|
+AT_CHECK([sed -i 's/^ReloadPolicy=.*/ReloadPolicy=INPUT:REJECT,FORWARD:ACCEPT/' ./firewalld.conf])
|
||||||
|
+dnl call RELOAD twice, to see more action about the ReloadPolicy.
|
||||||
|
+FWD_RELOAD()
|
||||||
|
+FWD_RELOAD()
|
||||||
|
+
|
||||||
|
+AT_CHECK([sed -i 's/^ReloadPolicy=.*/ReloadPolicy=REJECT/' ./firewalld.conf])
|
||||||
|
+FWD_RELOAD()
|
||||||
|
+
|
||||||
|
+FWD_END_TEST()
|
||||||
|
diff --git a/src/tests/unit/test_firewalld_conf.py b/src/tests/unit/test_firewalld_conf.py
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000000..0ce1fd279f91
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/tests/unit/test_firewalld_conf.py
|
||||||
|
@@ -0,0 +1,68 @@
|
||||||
|
+# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
+
|
||||||
|
+import firewall.core.io.firewalld_conf
|
||||||
|
+import firewall.config
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+def test_reload_policy():
|
||||||
|
+ def t(value, expected_valid=True, **kw):
|
||||||
|
+
|
||||||
|
+ expected = {
|
||||||
|
+ "INPUT": "DROP",
|
||||||
|
+ "FORWARD": "DROP",
|
||||||
|
+ "OUTPUT": "DROP",
|
||||||
|
+ }
|
||||||
|
+ for k, v in kw.items():
|
||||||
|
+ assert k in expected
|
||||||
|
+ expected[k] = v
|
||||||
|
+
|
||||||
|
+ try:
|
||||||
|
+ parsed = (
|
||||||
|
+ firewall.core.io.firewalld_conf.firewalld_conf._parse_reload_policy(
|
||||||
|
+ value
|
||||||
|
+ )
|
||||||
|
+ )
|
||||||
|
+ except ValueError:
|
||||||
|
+ assert not expected_valid
|
||||||
|
+ return
|
||||||
|
+
|
||||||
|
+ assert parsed == expected
|
||||||
|
+ assert expected_valid
|
||||||
|
+
|
||||||
|
+ unparsed = (
|
||||||
|
+ firewall.core.io.firewalld_conf.firewalld_conf._unparse_reload_policy(
|
||||||
|
+ parsed
|
||||||
|
+ )
|
||||||
|
+ )
|
||||||
|
+ parsed2 = firewall.core.io.firewalld_conf.firewalld_conf._parse_reload_policy(
|
||||||
|
+ unparsed
|
||||||
|
+ )
|
||||||
|
+ assert parsed2 == parsed
|
||||||
|
+
|
||||||
|
+ t(None)
|
||||||
|
+ t("")
|
||||||
|
+ t(" ")
|
||||||
|
+ t(" input: ACCept ", INPUT="ACCEPT")
|
||||||
|
+ t(
|
||||||
|
+ "forward:DROP, forward : REJEct; input: ACCept ",
|
||||||
|
+ INPUT="ACCEPT",
|
||||||
|
+ FORWARD="REJECT",
|
||||||
|
+ )
|
||||||
|
+ t(" accept ", INPUT="ACCEPT", FORWARD="ACCEPT", OUTPUT="ACCEPT")
|
||||||
|
+ t("REJECT", INPUT="REJECT", FORWARD="REJECT", OUTPUT="REJECT")
|
||||||
|
+ t("forward=REJECT", FORWARD="REJECT")
|
||||||
|
+ t("forward=REJECT , input=accept", FORWARD="REJECT", INPUT="ACCEPT")
|
||||||
|
+ t("forward=REJECT , xinput=accept", expected_valid=False)
|
||||||
|
+ t("forward=REJECT, ACCEPT", expected_valid=False)
|
||||||
|
+
|
||||||
|
+ def _norm(reload_policy):
|
||||||
|
+ parsed = firewall.core.io.firewalld_conf.firewalld_conf._parse_reload_policy(
|
||||||
|
+ reload_policy
|
||||||
|
+ )
|
||||||
|
+ return firewall.core.io.firewalld_conf.firewalld_conf._unparse_reload_policy(
|
||||||
|
+ parsed
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ assert firewall.config.FALLBACK_RELOAD_POLICY == _norm(
|
||||||
|
+ firewall.config.FALLBACK_RELOAD_POLICY
|
||||||
|
+ )
|
||||||
|
--
|
||||||
|
2.43.5
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
Summary: A firewall daemon with D-Bus interface providing a dynamic firewall
|
Summary: A firewall daemon with D-Bus interface providing a dynamic firewall
|
||||||
Name: firewalld
|
Name: firewalld
|
||||||
Version: 1.3.4
|
Version: 1.3.4
|
||||||
Release: 4%{?dist}
|
Release: 5%{?dist}
|
||||||
URL: http://www.firewalld.org
|
URL: http://www.firewalld.org
|
||||||
License: GPLv2+
|
License: GPLv2+
|
||||||
Source0: https://github.com/firewalld/firewalld/releases/download/v%{version}/firewalld-%{version}.tar.bz2
|
Source0: https://github.com/firewalld/firewalld/releases/download/v%{version}/firewalld-%{version}.tar.bz2
|
||||||
@ -12,6 +12,9 @@ Patch4: 0004-v1.4.0-test-direct-avoid-iptables-flush-if-using-nft.patch
|
|||||||
Patch5: 0005-v2.0.0-feat-service-add-OpenTelemetry-OTLP-service.patch
|
Patch5: 0005-v2.0.0-feat-service-add-OpenTelemetry-OTLP-service.patch
|
||||||
Patch6: 0006-v2.1.0-feat-icmp-add-ICMPv6-Multicast-Listener-Disco.patch
|
Patch6: 0006-v2.1.0-feat-icmp-add-ICMPv6-Multicast-Listener-Disco.patch
|
||||||
Patch7: 0007-v2.1.0-fix-rich-validate-service-name-of-rich-rule.patch
|
Patch7: 0007-v2.1.0-fix-rich-validate-service-name-of-rich-rule.patch
|
||||||
|
Patch8: 0008-v2.1.0-improvement-nftables-do-not-track-rule-handle.patch
|
||||||
|
Patch9: 0009-v2.1.0-improvement-fw-make-set_policy-DROP-more-flex.patch
|
||||||
|
Patch10: 0010-v2.1.0-feat-fw-add-ReloadPolicy-option-in-firewalld..patch
|
||||||
BuildArch: noarch
|
BuildArch: noarch
|
||||||
BuildRequires: autoconf
|
BuildRequires: autoconf
|
||||||
BuildRequires: automake
|
BuildRequires: automake
|
||||||
@ -235,6 +238,9 @@ rm -rf %{buildroot}%{_datadir}/firewalld/testsuite
|
|||||||
%{_mandir}/man1/firewall-config*.1*
|
%{_mandir}/man1/firewall-config*.1*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Mon Jul 01 2024 Eric Garver <egarver@redhat.com> - 1.3.4-5
|
||||||
|
- feat(fw): add ReloadPolicy option in firewalld.conf
|
||||||
|
|
||||||
* Mon Jul 01 2024 Eric Garver <egarver@redhat.com> - 1.3.4-4
|
* Mon Jul 01 2024 Eric Garver <egarver@redhat.com> - 1.3.4-4
|
||||||
- fix(rich): validate service name of rich rule
|
- fix(rich): validate service name of rich rule
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user