Blame SOURCES/0003-fw-if-failure-occurs-during-startup-set-state-to-FAI.patch

e3f863
From 9e4bf24e1e0a5d54398d2220f0a5217eff0704a7 Mon Sep 17 00:00:00 2001
e3f863
From: Eric Garver <e@erig.me>
e3f863
Date: Mon, 13 Aug 2018 16:53:46 -0400
e3f863
Subject: [PATCH 3/4] fw: if failure occurs during startup set state to FAILED
e3f863
e3f863
Previously if a failure occurred at startup firewalld would get stuck in
e3f863
INIT state and the policy would remain as "DROP". This commit changes
e3f863
that behavior and introduces a new state "FAILED", which means a failure
e3f863
occurred and we're running in a failed state. Policy is set to "ACCEPT"
e3f863
so as to hopefully prevent locking out an admin.
e3f863
e3f863
(cherry picked from commit f475bd2293b7ba01ad4b56b68bef1b61d01526f0)
e3f863
---
e3f863
 doc/xml/firewall-cmd.xml.in         |   2 +-
e3f863
 doc/xml/firewalld.dbus.xml          |   2 +-
e3f863
 src/firewall-cmd                    |   2 +
e3f863
 src/firewall/core/fw.py             | 131 +++++++++++++++-------------
e3f863
 src/firewall/errors.py              |   1 +
e3f863
 src/tests/regression/rhbz1498923.at |   8 +-
e3f863
 6 files changed, 83 insertions(+), 63 deletions(-)
e3f863
e3f863
diff --git a/doc/xml/firewall-cmd.xml.in b/doc/xml/firewall-cmd.xml.in
e3f863
index 32c89591db86..c2606553e549 100644
e3f863
--- a/doc/xml/firewall-cmd.xml.in
e3f863
+++ b/doc/xml/firewall-cmd.xml.in
e3f863
@@ -118,7 +118,7 @@
e3f863
 	  <term><option>--state</option></term>
e3f863
 	  <listitem>
e3f863
 	    <para>
e3f863
-	      Check whether the firewalld daemon is active (i.e. running). Returns an exit code 0 if it is active, <replaceable>NOT_RUNNING</replaceable> otherwise (see <xref linkend="exit_codes"/>). This will also print the state to <replaceable>STDOUT</replaceable>.
e3f863
+	      Check whether the firewalld daemon is active (i.e. running). Returns an exit code 0 if it is active, <replaceable>RUNNING_BUT_FAILED</replaceable> if failure occurred on startup, <replaceable>NOT_RUNNING</replaceable> otherwise. See <xref linkend="exit_codes"/>. This will also print the state to <replaceable>STDOUT</replaceable>.
e3f863
 	    </para>
e3f863
 	  </listitem>
e3f863
 	</varlistentry>
e3f863
diff --git a/doc/xml/firewalld.dbus.xml b/doc/xml/firewalld.dbus.xml
e3f863
index acdbb5fd6e00..ec82d4cad077 100644
e3f863
--- a/doc/xml/firewalld.dbus.xml
e3f863
+++ b/doc/xml/firewalld.dbus.xml
e3f863
@@ -488,7 +488,7 @@
e3f863
           </varlistentry>
e3f863
           <varlistentry id="FirewallD1.Properties.state">
e3f863
             <term><parameter>state</parameter> - s - (ro)</term>
e3f863
-            <listitem><para>firewalld state. This can be either <literal>INIT</literal> or <literal>RUNNING</literal>. In <literal>INIT</literal> state, firewalld is starting up and initializing.</para></listitem>
e3f863
+            <listitem><para>firewalld state. This can be either <literal>INIT</literal>, <literal>FAILED</literal>, or <literal>RUNNING</literal>. In <literal>INIT</literal> state, firewalld is starting up and initializing. In <literal>FAILED</literal> state, firewalld completely started but experienced a failure.</para></listitem>
e3f863
           </varlistentry>
e3f863
           <varlistentry id="FirewallD1.Properties.version">
e3f863
             <term><parameter>version</parameter> - s - (ro)</term>
e3f863
diff --git a/src/firewall-cmd b/src/firewall-cmd
e3f863
index b80115564e1b..12e18bb88a54 100755
e3f863
--- a/src/firewall-cmd
e3f863
+++ b/src/firewall-cmd
e3f863
@@ -2022,6 +2022,8 @@ elif a.state:
e3f863
     state = fw.get_property("state")
e3f863
     if state == "RUNNING":
e3f863
         cmd.print_and_exit ("running")
e3f863
+    elif state == "FAILED":
e3f863
+        cmd.print_and_exit("failed", errors.RUNNING_BUT_FAILED)
e3f863
     else:
e3f863
         cmd.print_and_exit ("not running", errors.NOT_RUNNING)
e3f863
 elif a.get_log_denied:
e3f863
diff --git a/src/firewall/core/fw.py b/src/firewall/core/fw.py
e3f863
index 1ff36f18cd99..5b706d6d3e80 100644
e3f863
--- a/src/firewall/core/fw.py
e3f863
+++ b/src/firewall/core/fw.py
e3f863
@@ -451,11 +451,16 @@ class Firewall(object):
e3f863
             tm2 = time.time()
e3f863
             log.debug2("Flushing and applying took %f seconds" % (tm2 - tm1))
e3f863
 
e3f863
-        self._state = "RUNNING"
e3f863
-
e3f863
     def start(self):
e3f863
-        self._start()
e3f863
-        self.set_policy("ACCEPT")
e3f863
+        try:
e3f863
+            self._start()
e3f863
+        except Exception:
e3f863
+            self._state = "FAILED"
e3f863
+            self.set_policy("ACCEPT")
e3f863
+            raise
e3f863
+        else:
e3f863
+            self._state = "RUNNING"
e3f863
+            self.set_policy("ACCEPT")
e3f863
 
e3f863
     def _loader(self, path, reader_type, combine=False):
e3f863
         # combine: several zone files are getting combined into one obj
e3f863
@@ -905,64 +910,70 @@ class Firewall(object):
e3f863
     def reload(self, stop=False):
e3f863
         _panic = self._panic
e3f863
 
e3f863
-        # save zone interfaces
e3f863
-        _zone_interfaces = { }
e3f863
-        for zone in self.zone.get_zones():
e3f863
-            _zone_interfaces[zone] = self.zone.get_settings(zone)["interfaces"]
e3f863
-        # save direct config
e3f863
-        _direct_config = self.direct.get_runtime_config()
e3f863
-        _old_dz = self.get_default_zone()
e3f863
-
e3f863
-        # stop
e3f863
-        self.cleanup()
e3f863
-
e3f863
-        self.set_policy("DROP")
e3f863
-
e3f863
-        # start
e3f863
-        self._start(reload=True, complete_reload=stop)
e3f863
-
e3f863
-        # handle interfaces in the default zone and move them to the new
e3f863
-        # default zone if it changed
e3f863
-        _new_dz = self.get_default_zone()
e3f863
-        if _new_dz != _old_dz:
e3f863
-            # if_new_dz has been introduced with the reload, we need to add it
e3f863
-            # https://github.com/firewalld/firewalld/issues/53
e3f863
-            if _new_dz not in _zone_interfaces:
e3f863
-                _zone_interfaces[_new_dz] = { }
e3f863
-            # default zone changed. Move interfaces from old default zone to
e3f863
-            # the new one.
e3f863
-            for iface, settings in list(_zone_interfaces[_old_dz].items()):
e3f863
-                if settings["__default__"]:
e3f863
-                    # move only those that were added to default zone
e3f863
-                    # (not those that were added to specific zone same as
e3f863
-                    # default)
e3f863
-                    _zone_interfaces[_new_dz][iface] = \
e3f863
-                        _zone_interfaces[_old_dz][iface]
e3f863
-                    del _zone_interfaces[_old_dz][iface]
e3f863
-
e3f863
-        # add interfaces to zones again
e3f863
-        for zone in self.zone.get_zones():
e3f863
-            if zone in _zone_interfaces:
e3f863
-                self.zone.set_settings(zone, { "interfaces":
e3f863
-                                               _zone_interfaces[zone] })
e3f863
-                del _zone_interfaces[zone]
e3f863
+        try:
e3f863
+            # save zone interfaces
e3f863
+            _zone_interfaces = { }
e3f863
+            for zone in self.zone.get_zones():
e3f863
+                _zone_interfaces[zone] = self.zone.get_settings(zone)["interfaces"]
e3f863
+            # save direct config
e3f863
+            _direct_config = self.direct.get_runtime_config()
e3f863
+            _old_dz = self.get_default_zone()
e3f863
+
e3f863
+            # stop
e3f863
+            self.cleanup()
e3f863
+
e3f863
+            self.set_policy("DROP")
e3f863
+
e3f863
+            self._start(reload=True, complete_reload=stop)
e3f863
+
e3f863
+            # handle interfaces in the default zone and move them to the new
e3f863
+            # default zone if it changed
e3f863
+            _new_dz = self.get_default_zone()
e3f863
+            if _new_dz != _old_dz:
e3f863
+                # if_new_dz has been introduced with the reload, we need to add it
e3f863
+                # https://github.com/firewalld/firewalld/issues/53
e3f863
+                if _new_dz not in _zone_interfaces:
e3f863
+                    _zone_interfaces[_new_dz] = { }
e3f863
+                # default zone changed. Move interfaces from old default zone to
e3f863
+                # the new one.
e3f863
+                for iface, settings in list(_zone_interfaces[_old_dz].items()):
e3f863
+                    if settings["__default__"]:
e3f863
+                        # move only those that were added to default zone
e3f863
+                        # (not those that were added to specific zone same as
e3f863
+                        # default)
e3f863
+                        _zone_interfaces[_new_dz][iface] = \
e3f863
+                            _zone_interfaces[_old_dz][iface]
e3f863
+                        del _zone_interfaces[_old_dz][iface]
e3f863
+
e3f863
+            # add interfaces to zones again
e3f863
+            for zone in self.zone.get_zones():
e3f863
+                if zone in _zone_interfaces:
e3f863
+                    self.zone.set_settings(zone, { "interfaces":
e3f863
+                                                   _zone_interfaces[zone] })
e3f863
+                    del _zone_interfaces[zone]
e3f863
+                else:
e3f863
+                    log.info1("New zone '%s'.", zone)
e3f863
+            if len(_zone_interfaces) > 0:
e3f863
+                for zone in list(_zone_interfaces.keys()):
e3f863
+                    log.info1("Lost zone '%s', zone interfaces dropped.", zone)
e3f863
+                    del _zone_interfaces[zone]
e3f863
+            del _zone_interfaces
e3f863
+
e3f863
+            # restore direct config
e3f863
+            self.direct.set_config(_direct_config)
e3f863
+
e3f863
+            # enable panic mode again if it has been enabled before or set policy
e3f863
+            # to ACCEPT
e3f863
+            if _panic:
e3f863
+                self.enable_panic_mode()
e3f863
             else:
e3f863
-                log.info1("New zone '%s'.", zone)
e3f863
-        if len(_zone_interfaces) > 0:
e3f863
-            for zone in list(_zone_interfaces.keys()):
e3f863
-                log.info1("Lost zone '%s', zone interfaces dropped.", zone)
e3f863
-                del _zone_interfaces[zone]
e3f863
-        del _zone_interfaces
e3f863
-
e3f863
-        # restore direct config
e3f863
-        self.direct.set_config(_direct_config)
e3f863
-
e3f863
-        # enable panic mode again if it has been enabled before or set policy
e3f863
-        # to ACCEPT
e3f863
-        if _panic:
e3f863
-            self.enable_panic_mode()
e3f863
-        else:
e3f863
+                self.set_policy("ACCEPT")
e3f863
+
e3f863
+            self._state = "RUNNING"
e3f863
+        except Exception:
e3f863
+            self._state = "FAILED"
e3f863
             self.set_policy("ACCEPT")
e3f863
+            raise
e3f863
 
e3f863
     # STATE
e3f863
 
e3f863
diff --git a/src/firewall/errors.py b/src/firewall/errors.py
e3f863
index 1cd604884c99..63d007191ffa 100644
e3f863
--- a/src/firewall/errors.py
e3f863
+++ b/src/firewall/errors.py
e3f863
@@ -97,6 +97,7 @@ MISSING_NAME        =  205
e3f863
 MISSING_SETTING     =  206
e3f863
 MISSING_FAMILY      =  207
e3f863
 
e3f863
+RUNNING_BUT_FAILED  =  251
e3f863
 NOT_RUNNING         =  252
e3f863
 NOT_AUTHORIZED      =  253
e3f863
 UNKNOWN_ERROR       =  254
e3f863
diff --git a/src/tests/regression/rhbz1498923.at b/src/tests/regression/rhbz1498923.at
e3f863
index 505a523d5cc4..bb0d841db2a7 100644
e3f863
--- a/src/tests/regression/rhbz1498923.at
e3f863
+++ b/src/tests/regression/rhbz1498923.at
e3f863
@@ -1,5 +1,11 @@
e3f863
 FWD_START_TEST([invalid direct rule causes reload error])
e3f863
 FWD_CHECK([-q --permanent --direct --add-rule ipv4 filter INPUT 0 -p tcp --dport 8080 -j ACCEPT])
e3f863
 FWD_CHECK([-q --permanent --direct --add-rule ipv4 filter INPUT 1 --a-bogus-flag])
e3f863
-FWD_RELOAD(13, [ignore], [ignore])
e3f863
+FWD_RELOAD(13, [ignore], [ignore], 251)
e3f863
+FWD_CHECK([--state], 251, [ignore], [failed
e3f863
+])
e3f863
+
e3f863
+dnl now remove the bad rule and reload successfully
e3f863
+FWD_CHECK([-q --permanent --direct --remove-rule ipv4 filter INPUT 1 --a-bogus-flag])
e3f863
+FWD_RELOAD
e3f863
 FWD_END_TEST([-e '/.*a-bogus-flag.*/d'])
e3f863
-- 
e3f863
2.18.0
e3f863