firewalld: Ignore errors with DBus API when firewalld is not running

Closes: #1782.

This restores the API to the earlier behavior of ignoring errors when firewalld
is not running. This may not be the best approach however.

- Ignore errors on all operations when firewalld is not running. This include
enable/disable service, list interfaces of a zone, get service ports and get
enabled service.

- Log errors when firewalld is not running.

- ALREADY_ENABLE and NOT_ENABLED errors already ignored during enable/disable
service operations respectively.

Tests successfully executed:

- Turn off firewalld and perform following operations. They should all log an
error that firewalld is not running.

  - Visit app page of an app that works only on internal networks such as
  Privoxy. It should show that there are no internal networks.

  - Run diagnostics of an app. It should show ports for a service as empty list.

  - Enable/disable an app, it should enable/disable without failure.

  - Visit firewall app page. It should show that firewalld is not running.

- Perform all the about operations without error message showing up and with
expected results.

Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: Veiko Aasa <veiko17@disroot.org>
This commit is contained in:
Sunil Mohan Adapa 2020-02-19 11:35:03 -08:00 committed by Veiko Aasa
parent 50a087dfee
commit 5c17c8c31e
No known key found for this signature in database
GPG Key ID: 478539CAE680674E

View File

@ -4,6 +4,7 @@ FreedomBox app to configure a firewall.
"""
import contextlib
import logging
from django.utils.translation import ugettext_lazy as _
@ -38,6 +39,8 @@ _port_details = {}
app = None
logger = logging.getLogger(__name__)
_DBUS_NAME = 'org.fedoraproject.FirewallD1'
_FIREWALLD_OBJECT = '/org/fedoraproject/FirewallD1'
_FIREWALLD_INTERFACE = 'org.fedoraproject.FirewallD1'
@ -118,12 +121,22 @@ def _get_dbus_proxy(object, interface):
@contextlib.contextmanager
def ignore_dbus_error(ignored_exception):
def ignore_dbus_error(dbus_error=None, service_error=None):
try:
yield
except glib.Error as exception:
parts = exception.message.split(':')
if parts[0] != 'GDBus.Error' or parts[2].strip() != ignored_exception:
if parts[0] != 'GDBus.Error':
raise
if (dbus_error and parts[1].strip() == 'org.freedesktop.DBus.Error.' +
dbus_error):
logger.error('Firewalld is not running.')
pass
elif (service_error and parts[2].strip() == service_error):
logger.warning('Ignoring firewall exception: %s', service_error)
pass
else:
raise
@ -138,8 +151,11 @@ def get_enabled_status():
def get_enabled_services(zone):
"""Return the status of various services currently enabled"""
zone_proxy = _get_dbus_proxy(_FIREWALLD_OBJECT, _ZONE_INTERFACE)
return zone_proxy.getServices('(s)', zone)
with ignore_dbus_error(dbus_error='ServiceUnknown'):
zone_proxy = _get_dbus_proxy(_FIREWALLD_OBJECT, _ZONE_INTERFACE)
return zone_proxy.getServices('(s)', zone)
return [] # When firewalld is not running
def get_port_details(service_port):
@ -160,34 +176,39 @@ def get_port_details(service_port):
def get_interfaces(zone):
"""Return the list of interfaces in a zone."""
zone_proxy = _get_dbus_proxy(_FIREWALLD_OBJECT, _ZONE_INTERFACE)
return zone_proxy.getInterfaces('(s)', zone)
with ignore_dbus_error(dbus_error='ServiceUnknown'):
zone_proxy = _get_dbus_proxy(_FIREWALLD_OBJECT, _ZONE_INTERFACE)
return zone_proxy.getInterfaces('(s)', zone)
return [] # When firewalld is not running
def add_service(port, zone):
"""Enable a service in firewall"""
zone_proxy = _get_dbus_proxy(_FIREWALLD_OBJECT, _ZONE_INTERFACE)
with ignore_dbus_error('ALREADY_ENABLED'):
zone_proxy.addService('(ssi)', zone, port, 0)
with ignore_dbus_error(dbus_error='ServiceUnknown'):
zone_proxy = _get_dbus_proxy(_FIREWALLD_OBJECT, _ZONE_INTERFACE)
with ignore_dbus_error(service_error='ALREADY_ENABLED'):
zone_proxy.addService('(ssi)', zone, port, 0)
config = _get_dbus_proxy(_CONFIG_OBJECT, _CONFIG_INTERFACE)
zone_path = config.getZoneByName('(s)', zone)
config_zone = _get_dbus_proxy(zone_path, _CONFIG_ZONE_INTERFACE)
with ignore_dbus_error('ALREADY_ENABLED'):
config_zone.addService('(s)', port)
config = _get_dbus_proxy(_CONFIG_OBJECT, _CONFIG_INTERFACE)
zone_path = config.getZoneByName('(s)', zone)
config_zone = _get_dbus_proxy(zone_path, _CONFIG_ZONE_INTERFACE)
with ignore_dbus_error(service_error='ALREADY_ENABLED'):
config_zone.addService('(s)', port)
def remove_service(port, zone):
"""Remove a service in firewall"""
zone_proxy = _get_dbus_proxy(_FIREWALLD_OBJECT, _ZONE_INTERFACE)
with ignore_dbus_error('NOT_ENABLED'):
zone_proxy.removeService('(ss)', zone, port)
with ignore_dbus_error(dbus_error='ServiceUnknown'):
zone_proxy = _get_dbus_proxy(_FIREWALLD_OBJECT, _ZONE_INTERFACE)
with ignore_dbus_error(service_error='NOT_ENABLED'):
zone_proxy.removeService('(ss)', zone, port)
config = _get_dbus_proxy(_CONFIG_OBJECT, _CONFIG_INTERFACE)
zone_path = config.getZoneByName('(s)', zone)
config_zone = _get_dbus_proxy(zone_path, _CONFIG_ZONE_INTERFACE)
with ignore_dbus_error('NOT_ENABLED'):
config_zone.removeService('(s)', port)
config = _get_dbus_proxy(_CONFIG_OBJECT, _CONFIG_INTERFACE)
zone_path = config.getZoneByName('(s)', zone)
config_zone = _get_dbus_proxy(zone_path, _CONFIG_ZONE_INTERFACE)
with ignore_dbus_error(service_error='NOT_ENABLED'):
config_zone.removeService('(s)', port)
def _run(arguments, superuser=False):