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