mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-01-21 07:55:00 +00:00
firewall: Use privileged decorator, drop showing running status
- If a daemon is not-running, we already show an error message to the user. Use that mechanism instead of the custom one. Tests: - Functional tests work. - Initial setup for firewall on first boot works. - Default zone of the firewalld is set to external in /etc/firewalld.conf - Status of various apps is shown properly in the app page - If firewalld is not running, the app page is still displayed properly and message that firewalld is not running is shown. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
parent
5389303e98
commit
a62b7c7522
@ -1,14 +1,11 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""
|
||||
FreedomBox app to configure a firewall.
|
||||
"""
|
||||
"""FreedomBox app to configure a firewall."""
|
||||
|
||||
import contextlib
|
||||
import logging
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from plinth import actions
|
||||
from plinth import app as app_module
|
||||
from plinth import cfg, menu
|
||||
from plinth.daemon import Daemon
|
||||
@ -16,7 +13,7 @@ from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.package import Packages, install
|
||||
from plinth.utils import Version, format_lazy, import_from_gi
|
||||
|
||||
from . import manifest
|
||||
from . import manifest, privileged
|
||||
|
||||
gio = import_from_gi('Gio', '2.0')
|
||||
glib = import_from_gi('GLib', '2.0')
|
||||
@ -98,7 +95,7 @@ class FirewallApp(app_module.App):
|
||||
|
||||
def _run_setup():
|
||||
"""Run firewalld setup."""
|
||||
_run(['setup'], superuser=True)
|
||||
privileged.setup()
|
||||
add_service('http', 'external')
|
||||
add_service('http', 'internal')
|
||||
add_service('https', 'external')
|
||||
@ -171,17 +168,8 @@ def try_with_reload(operation):
|
||||
operation()
|
||||
|
||||
|
||||
def get_enabled_status():
|
||||
"""Return whether firewall is enabled"""
|
||||
output = _run(['get-status'], superuser=True)
|
||||
if not output:
|
||||
return False
|
||||
else:
|
||||
return output.split()[0] == 'running'
|
||||
|
||||
|
||||
def get_enabled_services(zone):
|
||||
"""Return the status of various services currently enabled"""
|
||||
"""Return the status of various services currently enabled."""
|
||||
with ignore_dbus_error(dbus_error='ServiceUnknown'):
|
||||
zone_proxy = _get_dbus_proxy(_FIREWALLD_OBJECT, _ZONE_INTERFACE)
|
||||
return zone_proxy.getServices('(s)', zone)
|
||||
@ -190,7 +178,7 @@ def get_enabled_services(zone):
|
||||
|
||||
|
||||
def get_port_details(service_port):
|
||||
"""Return the port types and numbers for a service port"""
|
||||
"""Return the port types and numbers for a service port."""
|
||||
try:
|
||||
return _port_details[service_port]
|
||||
except KeyError:
|
||||
@ -215,7 +203,7 @@ def get_interfaces(zone):
|
||||
|
||||
|
||||
def add_service(port, zone):
|
||||
"""Enable a service in firewall"""
|
||||
"""Enable a service in firewall."""
|
||||
with ignore_dbus_error(dbus_error='ServiceUnknown'):
|
||||
zone_proxy = _get_dbus_proxy(_FIREWALLD_OBJECT, _ZONE_INTERFACE)
|
||||
with ignore_dbus_error(service_error='ALREADY_ENABLED'):
|
||||
@ -229,7 +217,7 @@ def add_service(port, zone):
|
||||
|
||||
|
||||
def remove_service(port, zone):
|
||||
"""Remove a service in firewall"""
|
||||
"""Remove a service in firewall."""
|
||||
with ignore_dbus_error(dbus_error='ServiceUnknown'):
|
||||
zone_proxy = _get_dbus_proxy(_FIREWALLD_OBJECT, _ZONE_INTERFACE)
|
||||
with ignore_dbus_error(service_error='NOT_ENABLED'):
|
||||
@ -240,13 +228,3 @@ def remove_service(port, 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):
|
||||
"""Run an given command and raise exception if there was an error"""
|
||||
command = 'firewall'
|
||||
|
||||
if superuser:
|
||||
return actions.superuser_run(command, arguments)
|
||||
else:
|
||||
return actions.run(command, arguments)
|
||||
|
||||
48
actions/firewall → plinth/modules/firewall/privileged.py
Executable file → Normal file
48
actions/firewall → plinth/modules/firewall/privileged.py
Executable file → Normal file
@ -1,31 +1,12 @@
|
||||
#!/usr/bin/python3
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""
|
||||
Configuration helper for FreedomBox firewall interface.
|
||||
"""
|
||||
"""Configuration helper for FreedomBox firewall interface."""
|
||||
|
||||
import argparse
|
||||
import subprocess
|
||||
|
||||
import augeas
|
||||
|
||||
from plinth import action_utils
|
||||
|
||||
|
||||
def parse_arguments():
|
||||
"""Return parsed command line arguments as dictionary"""
|
||||
parser = argparse.ArgumentParser()
|
||||
subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
|
||||
|
||||
# Setup
|
||||
subparsers.add_parser('setup', help='Perform basic firewall setup')
|
||||
|
||||
# Get status
|
||||
subparsers.add_parser('get-status',
|
||||
help='Get whether firewalld is running')
|
||||
|
||||
subparsers.required = True
|
||||
return parser.parse_args()
|
||||
from plinth.actions import privileged
|
||||
|
||||
|
||||
def _flush_iptables_rules():
|
||||
@ -81,26 +62,11 @@ def set_firewall_backend(backend):
|
||||
action_utils.service_restart('firewalld')
|
||||
|
||||
|
||||
def subcommand_setup(_):
|
||||
@privileged
|
||||
def setup():
|
||||
"""Perform basic firewalld setup."""
|
||||
action_utils.service_enable('firewalld')
|
||||
subprocess.call(['firewall-cmd', '--set-default-zone=external'])
|
||||
subprocess.run(['firewall-cmd', '--set-default-zone=external'],
|
||||
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
|
||||
check=True)
|
||||
set_firewall_backend('nftables')
|
||||
|
||||
|
||||
def subcommand_get_status(_):
|
||||
"""Print status of the firewalld service"""
|
||||
subprocess.call(['firewall-cmd', '--state'])
|
||||
|
||||
|
||||
def main():
|
||||
"""Parse arguments and perform all duties"""
|
||||
arguments = parse_arguments()
|
||||
|
||||
subcommand = arguments.subcommand.replace('-', '_')
|
||||
subcommand_method = globals()['subcommand_' + subcommand]
|
||||
subcommand_method(arguments)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@ -15,97 +15,82 @@
|
||||
|
||||
<h3>{% trans "Status" %}</h3>
|
||||
|
||||
{% if firewall_status == 'not_running' %}
|
||||
<div class="table-responsive">
|
||||
<table class='table table-autowidth'>
|
||||
<thead>
|
||||
<th>{% trans "Service/Port" %}</th>
|
||||
<th>{% trans "Status" %}</th>
|
||||
</thead>
|
||||
|
||||
<p>
|
||||
{% blocktrans trimmed %}
|
||||
Firewall daemon is not running. Please run it. Firewall comes
|
||||
enabled by default on {{ box_name }}. On any Debian based
|
||||
system (such as {{ box_name }}) you may run it using the
|
||||
command 'service firewalld start' or in case of a system with
|
||||
systemd 'systemctl start firewalld'.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
|
||||
{% else %}
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class='table table-autowidth'>
|
||||
<thead>
|
||||
<th>{% trans "Service/Port" %}</th>
|
||||
<th>{% trans "Status" %}</th>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% for component in components|dictsort:"name" %}
|
||||
{% if component.ports %}
|
||||
<tr>
|
||||
<td class="app-name">
|
||||
<a class="dropdown-toggle" href="#"
|
||||
data-toggle="collapse" role="button"
|
||||
data-target=".{{component.component_id}}"
|
||||
aria-expanded="false"
|
||||
aria-controls="{{component.component_id}}">
|
||||
{{ component.name }}</a>
|
||||
<tbody>
|
||||
{% for component in components|dictsort:"name" %}
|
||||
{% if component.ports %}
|
||||
<tr>
|
||||
<td class="app-name">
|
||||
<a class="dropdown-toggle" href="#"
|
||||
data-toggle="collapse" role="button"
|
||||
data-target=".{{component.component_id}}"
|
||||
aria-expanded="false"
|
||||
aria-controls="{{component.component_id}}">
|
||||
{{ component.name }}</a>
|
||||
</td>
|
||||
<td class="app-status">
|
||||
{% if component.is_enabled %}
|
||||
<span class='badge badge-success'>
|
||||
{% trans "Enabled" %}</span>
|
||||
{% else %}
|
||||
<span class='badge badge-warning'>
|
||||
{% trans "Disabled" %}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% for port in component.ports_details %}
|
||||
<tr class="collapse {{component.component_id}}">
|
||||
<td class='service'>
|
||||
<span class="service-name">{{ port.name }}</span>:
|
||||
{% for port_number, protocol in port.details %}
|
||||
{{ port_number }}/{{ protocol }}
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td class="app-status">
|
||||
{% if component.is_enabled %}
|
||||
<td class="service-status">
|
||||
{% if port.name in internal_enabled_ports and port.name in external_enabled_ports %}
|
||||
<span class='badge badge-success'>
|
||||
{% trans "Enabled" %}</span>
|
||||
{% else %}
|
||||
{% trans "Permitted" %}</span>
|
||||
{% elif port.name in internal_enabled_ports %}
|
||||
<span class='badge badge-warning'>
|
||||
{% trans "Disabled" %}</span>
|
||||
{% trans "Permitted (internal only)" %}</span>
|
||||
{% elif port.name in external_enabled_ports %}
|
||||
<span class='badge badge-warning'>
|
||||
{% trans "Permitted (external only)" %}</span>
|
||||
{% else %}
|
||||
<span class='badge badge-danger'>
|
||||
{% trans "Blocked" %}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% for port in component.ports_details %}
|
||||
<tr class="collapse {{component.component_id}}">
|
||||
<td class='service'>
|
||||
<span class="service-name">{{ port.name }}</span>:
|
||||
{% for port_number, protocol in port.details %}
|
||||
{{ port_number }}/{{ protocol }}
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td class="service-status">
|
||||
{% if port.name in internal_enabled_ports and port.name in external_enabled_ports %}
|
||||
<span class='badge badge-success'>
|
||||
{% trans "Permitted" %}</span>
|
||||
{% elif port.name in internal_enabled_ports %}
|
||||
<span class='badge badge-warning'>
|
||||
{% trans "Permitted (internal only)" %}</span>
|
||||
{% elif port.name in external_enabled_ports %}
|
||||
<span class='badge badge-warning'>
|
||||
{% trans "Permitted (external only)" %}</span>
|
||||
{% else %}
|
||||
<span class='badge badge-danger'>
|
||||
{% trans "Blocked" %}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<em>
|
||||
{% blocktrans trimmed %}
|
||||
The operation of the firewall is automatic. When you enable
|
||||
a service it is also permitted in the firewall and when you
|
||||
disable a service it is also disabled in the firewall.
|
||||
{% endblocktrans %}
|
||||
</em>
|
||||
</p>
|
||||
|
||||
<h3>{%trans "Advanced" %} </h3>
|
||||
<p>
|
||||
<p>
|
||||
<em>
|
||||
{% blocktrans trimmed %}
|
||||
Advanced firewall operations such as opening custom ports are provided
|
||||
by the <a href="/_cockpit/network/firewall">Cockpit</a> app.
|
||||
The operation of the firewall is automatic. When you enable
|
||||
a service it is also permitted in the firewall and when you
|
||||
disable a service it is also disabled in the firewall.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
{% endif %}
|
||||
</em>
|
||||
</p>
|
||||
|
||||
<h3>{%trans "Advanced" %} </h3>
|
||||
<p>
|
||||
{% blocktrans trimmed %}
|
||||
Advanced firewall operations such as opening custom ports are provided
|
||||
by the <a href="/_cockpit/network/firewall">Cockpit</a> app.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""
|
||||
FreedomBox app to configure a firewall.
|
||||
"""
|
||||
"""FreedomBox app to configure a firewall."""
|
||||
|
||||
from plinth import views
|
||||
from plinth.modules import firewall
|
||||
@ -11,23 +9,16 @@ from . import components
|
||||
|
||||
class FirewallAppView(views.AppView):
|
||||
"""Serve firewall index page."""
|
||||
|
||||
app_id = 'firewall'
|
||||
template_name = 'firewall.html'
|
||||
|
||||
def get_context_data(self, *args, **kwargs):
|
||||
"""Add additional context data for the template."""
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
|
||||
status = 'running' if firewall.get_enabled_status() else 'not_running'
|
||||
context['firewall_status'] = status
|
||||
|
||||
if status == 'running':
|
||||
context['components'] = components.Firewall.list()
|
||||
internal_enabled_ports = firewall.get_enabled_services(
|
||||
zone='internal')
|
||||
external_enabled_ports = firewall.get_enabled_services(
|
||||
zone='external')
|
||||
context['internal_enabled_ports'] = internal_enabled_ports
|
||||
context['external_enabled_ports'] = external_enabled_ports
|
||||
|
||||
context['components'] = components.Firewall.list()
|
||||
internal_enabled_ports = firewall.get_enabled_services(zone='internal')
|
||||
external_enabled_ports = firewall.get_enabled_services(zone='external')
|
||||
context['internal_enabled_ports'] = internal_enabled_ports
|
||||
context['external_enabled_ports'] = external_enabled_ports
|
||||
return context
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user