File 0001-chore-fw_zone-call-permanent-config-checks-at-runtim.patch of Package firewalld.23290

From 96a2f47c84ed7054dce8d3947a3f71022c5b4e75 Mon Sep 17 00:00:00 2001
From: Eric Garver <eric@garver.life>
Date: Tue, 9 Nov 2021 11:40:24 -0500
Subject: [PATCH] chore(fw_zone): call permanent config checks at runtime

Re-use the permanent configuration checks for runtime changes. As of
this commit, this is not yet checking anything new because the runtime
object instances are still using the settings dictionary. So this is
actually only checking the config that originated from the permanent
(on-disk) configuration.
---
 src/firewall/core/fw.py      | 51 ++++++++++++++++++++++++++++++++++++
 src/firewall/core/fw_zone.py |  4 ++-
 2 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/src/firewall/core/fw.py b/src/firewall/core/fw.py
index 15284a49..50e04616 100644
--- a/src/firewall/core/fw.py
+++ b/src/firewall/core/fw.py
@@ -128,6 +128,54 @@ class Firewall(object):
         self._rfc3964_ipv4 = config.FALLBACK_RFC3964_IPV4
         self._allow_zone_drifting = config.FALLBACK_ALLOW_ZONE_DRIFTING
 
+    def get_all_io_objects_dict(self):
+        """
+        Returns a dict of dicts of all runtime config objects.
+        """
+        conf_dict = {}
+        conf_dict["ipsets"] = {_ipset: self.ipset.get_ipset(_ipset) for _ipset in self.ipset.get_ipsets()}
+        conf_dict["helpers"] = {helper: self.helper.get_helper(helper) for helper in self.helper.get_helpers()}
+        conf_dict["icmptypes"] = {icmptype: self.icmptype.get_icmptype(icmptype) for icmptype in self.icmptype.get_icmptypes()}
+        conf_dict["services"] = {service: self.service.get_service(service) for service in self.service.get_services()}
+        conf_dict["zones"] = {zone: self.zone.get_zone(zone) for zone in self.zone.get_zones()}
+        conf_dict["policies"] = {policy: self.policy.get_policy(policy) for policy in self.policy.get_policies_not_derived_from_zone()}
+
+        # The runtime might not actually support all the defined icmptypes.
+        # This is the case if ipv6 (ip6tables) is disabled. Unfortunately users
+        # disable IPv6 and also expect the IPv6 stuff to be silently ignored.
+        # This is problematic for defaults that include IPv6 stuff, e.g. policy
+        # 'allow-host-ipv6'. Use this to make a better decision about errors vs
+        # warnings.
+        #
+        conf_dict["icmptypes_unsupported"] = {}
+        for icmptype in (set(self.config.get_icmptypes()).difference(
+                         set(self.icmptype.get_icmptypes()))):
+            conf_dict["icmptypes_unsupported"][icmptype] = self.config.get_icmptype(icmptype)
+        # Some icmptypes support multiple families. Add those that are missing
+        # support for a subset of families.
+        for icmptype in (set(self.config.get_icmptypes()).intersection(
+                         set(self.icmptype.get_icmptypes()))):
+            if icmptype not in self.ipv4_supported_icmp_types or \
+               icmptype not in self.ipv6_supported_icmp_types:
+                conf_dict["icmptypes_unsupported"][icmptype] = copy.copy(self.config.get_icmptype(icmptype))
+                conf_dict["icmptypes_unsupported"][icmptype].destination = []
+                if icmptype not in self.ipv4_supported_icmp_types:
+                    conf_dict["icmptypes_unsupported"][icmptype].destination.append("ipv4")
+                if icmptype not in self.ipv6_supported_icmp_types:
+                    conf_dict["icmptypes_unsupported"][icmptype].destination.append("ipv6")
+
+        return conf_dict
+
+    def full_check_config(self):
+        # we need to check in a well defined order because some io_objects will
+        # cross-check others
+        order = ["ipsets", "helpers", "icmptypes", "services", "zones", "policies"]
+        all_io_objects = self.get_all_io_objects_dict()
+        for io_obj_type in order:
+            io_objs = all_io_objects[io_obj_type]
+            for (name, io_obj) in io_objs.items():
+                io_obj.check_config_dict(io_obj.export_config_dict(), all_io_objects)
+
     def _check_tables(self):
         # check if iptables, ip6tables and ebtables are usable, else disable
         if self.ip4tables_enabled and \
@@ -1141,6 +1189,9 @@ class Firewall(object):
             self._firewalld_conf.set("DefaultZone", _zone)
             self._firewalld_conf.write()
 
+            if self._offline:
+                return
+
             # remove old default zone from ZONES and add new default zone
             self.zone.change_default_zone(_old_dz, _zone)
 
diff --git a/src/firewall/core/fw_zone.py b/src/firewall/core/fw_zone.py
index fde7037e..a8457744 100644
--- a/src/firewall/core/fw_zone.py
+++ b/src/firewall/core/fw_zone.py
@@ -48,7 +48,9 @@ class FirewallZone(object):
         self._zone_policies.clear()
 
     def new_transaction(self):
-        return FirewallTransaction(self._fw)
+        t = FirewallTransaction(self._fw)
+        t.add_pre(self._fw.full_check_config)
+        return t
 
     def policy_name_from_zones(self, fromZone, toZone):
         return "zone_{fromZone}_{toZone}".format(fromZone=fromZone, toZone=toZone)
-- 
2.34.1

openSUSE Build Service is sponsored by