firewall: Reload firewalld so it works with newly installed services

firewalld has no problem retrieving service information for just-installed
files, it only fails when adding/removing those services to zones. A reload is
needed before those services can be used.

Don't perform firewalld reload during setup.py or debian/postinst. Instead
reload when firewalld throws an error that it does not know a service. This
approach is more minimally intrusive and does not run reload operations when no
services need to be loaded, during Debian package building etc.

Closes: #376.

Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
Sunil Mohan Adapa 2020-05-07 15:21:35 -07:00 committed by James Valleroy
parent b763391dfb
commit 55f4573e93
No known key found for this signature in database
GPG Key ID: 77C0C75E7B650808
2 changed files with 45 additions and 0 deletions

View File

@ -142,6 +142,45 @@ def ignore_dbus_error(dbus_error=None, service_error=None):
raise
def parse_dbus_error(exception):
"""Parse a GDBus error."""
parts = exception.message.split(':')
if parts[0] != 'GDBus.Error' or \
parts[1] != 'org.fedoraproject.FirewallD1.Exception':
return None
return parts[2].strip()
def reload():
"""Reload firewalld."""
logger.info('Reloading firewalld')
with ignore_dbus_error(dbus_error='ServiceUnknown'):
proxy = _get_dbus_proxy(_FIREWALLD_OBJECT, _FIREWALLD_INTERFACE)
proxy.reload()
def try_with_reload(operation):
"""Try an operation and retry after firewalld reload.
When a service file is newly installed into /usr/lib/firewalld/services,
it's information can be immediately queried but the service can't be
added/removed from a zone. A firewalld reload is necessary. So, try an
operation and if it fails with INVALID_SERVICE error, reload firewalld and
try again.
"""
try:
operation()
except glib.Error as exception:
error = parse_dbus_error(exception)
if error != 'INVALID_SERVICE':
raise
reload()
operation()
def get_enabled_status():
"""Return whether firewall is enabled"""
output = _run(['get-status'], superuser=True)

View File

@ -51,7 +51,10 @@ class Firewall(app.FollowerComponent):
def enable(self):
"""Open firewall ports when the component is enabled."""
super().enable()
firewall.try_with_reload(self._enable)
def _enable(self):
"""Open firewall ports."""
internal_enabled_ports = firewall.get_enabled_services(zone='internal')
external_enabled_ports = firewall.get_enabled_services(zone='external')
@ -66,7 +69,10 @@ class Firewall(app.FollowerComponent):
def disable(self):
"""Close firewall ports when the component is disabled."""
super().disable()
firewall.try_with_reload(self._disable)
def _disable(self):
"""Close firewall ports."""
internal_enabled_ports = firewall.get_enabled_services(zone='internal')
external_enabled_ports = firewall.get_enabled_services(zone='external')