From 3ef1ed83ce076016d7e840e04f5babe156f729d4 Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa
Date: Sun, 27 Apr 2014 18:16:32 +0530
Subject: [PATCH] Add support for zones in firewall service
---
actions/firewall | 40 +++++++++++++------
lib/freedombox/first-run.d/90_firewall | 52 ++++++++++++++-----------
modules/installed/apps/owncloud.py | 2 +-
modules/installed/services/xmpp.py | 20 +++-------
modules/installed/system/firewall.py | 53 +++++++++++++++++++-------
service.py | 17 +++++----
6 files changed, 114 insertions(+), 70 deletions(-)
diff --git a/actions/firewall b/actions/firewall
index 88a921d2b..520115c24 100755
--- a/actions/firewall
+++ b/actions/firewall
@@ -22,8 +22,6 @@ Configuration helper for Plinth firewall inteface
"""
import argparse
-import os
-import re
import subprocess
@@ -37,18 +35,31 @@ def parse_arguments():
help='Get whether firewalld is installed')
# Get status
- subparsers.add_parser('get-status', help='Get whether firewalld is running')
+ subparsers.add_parser('get-status',
+ help='Get whether firewalld is running')
# Get service status
- subparsers.add_parser('get-enabled-services', help='Get list of enabled services')
+ get_enabled_services = subparsers.add_parser(
+ 'get-enabled-services', help='Get list of enabled services')
+ get_enabled_services.add_argument(
+ '--zone', help='Zone from which the list is to be retrieved',
+ required=True)
# Add a service
add_service = subparsers.add_parser('add-service', help='Add a service')
add_service.add_argument('service', help='Name of the service to add')
+ add_service.add_argument('--zone',
+ help='Zone to which service is to be added',
+ required=True)
# Remove a service status
- remove_service = subparsers.add_parser('remove-service', help='Remove a service')
- remove_service.add_argument('service', help='Name of the service to remove')
+ remove_service = subparsers.add_parser('remove-service',
+ help='Remove a service')
+ remove_service.add_argument('service',
+ help='Name of the service to remove')
+ remove_service.add_argument(
+ '--zone', help='Zone from which service is to be removed',
+ required=True)
return parser.parse_args()
@@ -66,21 +77,26 @@ def subcommand_get_status(_):
subprocess.call(['firewall-cmd', '--state'])
-def subcommand_get_enabled_services(_):
+def subcommand_get_enabled_services(arguments):
"""Print the status of variours services"""
- subprocess.call(['firewall-cmd', '--list-services'])
+ subprocess.call(['firewall-cmd', '--zone', arguments.zone,
+ '--list-services'])
def subcommand_add_service(arguments):
"""Permit a service in the firewall"""
- subprocess.call(['firewall-cmd', '--add-service', arguments.service])
- subprocess.call(['firewall-cmd', '--permanent', '--add-service', arguments.service])
+ subprocess.call(['firewall-cmd', '--zone', arguments.zone, '--add-service',
+ arguments.service])
+ subprocess.call(['firewall-cmd', '--zone', arguments.zone, '--permanent',
+ '--add-service', arguments.service])
def subcommand_remove_service(arguments):
"""Block a service in the firewall"""
- subprocess.call(['firewall-cmd', '--remove-service', arguments.service])
- subprocess.call(['firewall-cmd', '--permanent', '--remove-service', arguments.service])
+ subprocess.call(['firewall-cmd', '--zone', arguments.zone,
+ '--remove-service', arguments.service])
+ subprocess.call(['firewall-cmd', '--zone', arguments.zone, '--permanent',
+ '--remove-service', arguments.service])
def main():
diff --git a/lib/freedombox/first-run.d/90_firewall b/lib/freedombox/first-run.d/90_firewall
index dadd7fe74..9e53235b8 100755
--- a/lib/freedombox/first-run.d/90_firewall
+++ b/lib/freedombox/first-run.d/90_firewall
@@ -1,48 +1,56 @@
#!/bin/sh
-# Setup firewall rules for all the enabled services
-# Ideally all non essential services are enabled from Plinth
-# which automatically takes care of enabling appropirate firewall
-# ports. This file is used then for essential services and services
-# that are not yet configurable from Plinth.
+# Setup firewall rules for all the services enabled by default.
+# Ideally all non-essential services are enabled from Plinth which
+# automatically takes care of enabling appropirate firewall ports. The
+# following is then for essential services and services that are not
+# yet configurable from Plinth.
# HTTP (JWChat, ownCloud)
-firewall-cmd --permanent --add-service=http
+firewall-cmd --zone=external --permanent --add-service=http
+firewall-cmd --zone=internal --permanent --add-service=http
# HTTPS (Plinth, JWChat, ownCloud)
-firewall-cmd --permanent --add-service=https
+firewall-cmd --zone=external --permanent --add-service=https
+firewall-cmd --zone=internal --permanent --add-service=https
# Tor
-firewall-cmd --permanent --add-port=9050/tcp
+firewall-cmd --zone=internal --permanent --add-service=tor-socks
# NTP
-firewall-cmd --permanent --add-service=ntp
+firewall-cmd --zone=internal --permanent --add-service=ntp
# DNS
-firewall-cmd --permanent --add-service=dns
+firewall-cmd --zone=internal --permanent --add-service=dns
# mDNS
-firewall-cmd --permanent --add-service=mdns
+firewall-cmd --zone=internal --permanent --add-service=mdns
# DHCP
-firewall-cmd --permanent --add-service=dhcp
+firewall-cmd --zone=internal --permanent --add-service=dhcp
# Bootp Server and Client (not enabled)
-#firewall-cmd --permanent --add-port=67/tcp
-#firewall-cmd --permanent --add-port=67/udp
-#firewall-cmd --permanent --add-port=68/tcp
-#firewall-cmd --permanent --add-port=68/udp
+#firewall-cmd --zone=internal --permanent --add-port=67/tcp
+#firewall-cmd --zone=internal --permanent --add-port=67/udp
+#firewall-cmd --zone=internal --permanent --add-port=68/tcp
+#firewall-cmd --zone=internal --permanent --add-port=68/udp
# LDAP (not enabled)
-#firewall-cmd --permanent --add-service=ldap
-#firewall-cmd --permanent --add-service=ldaps
+#firewall-cmd --zone=internal --permanent --add-service=ldap
+#firewall-cmd --zone=internal --permanent --add-service=ldaps
# OpenVPN (not enabled)
-#firewall-cmd --permanent --add-service=openvpn
+#firewall-cmd --zone=external --permanent --add-service=openvpn
+#firewall-cmd --zone=internal --permanent --add-service=openvpn
# Privoxy
-firewall-cmd --permanent --add-port=8118/tcp
+firewall-cmd --zone=internal --permanent --add-service=privoxy
-# Obfsproxy
-firewall-cmd --permanent --add-port=40202/tcp
+# XMPP
+firewall-cmd --zone=external --permanent --add-service=xmpp-server
+firewall-cmd --zone=internal --permanent --add-service=xmpp-server
+firewall-cmd --zone=external --permanent --add-service=xmpp-client
+firewall-cmd --zone=internal --permanent --add-service=xmpp-client
+firewall-cmd --zone=external --permanent --add-service=xmpp-bosh
+firewall-cmd --zone=internal --permanent --add-service=xmpp-bosh
diff --git a/modules/installed/apps/owncloud.py b/modules/installed/apps/owncloud.py
index 9bfb84e9b..b3504a1b6 100644
--- a/modules/installed/apps/owncloud.py
+++ b/modules/installed/apps/owncloud.py
@@ -17,7 +17,7 @@ class Owncloud(PagePlugin, FormPlugin):
cfg.html_root.apps.menu.add_item("Owncloud", "icon-picture", "/apps/owncloud", 35)
self.service = service.Service('owncloud', _('ownCloud'),
- ['http', 'https'],
+ ['http', 'https'], is_external=True,
enabled=self.is_enabled)
def is_enabled(self):
diff --git a/modules/installed/services/xmpp.py b/modules/installed/services/xmpp.py
index 858137af8..46063bfc1 100644
--- a/modules/installed/services/xmpp.py
+++ b/modules/installed/services/xmpp.py
@@ -17,22 +17,14 @@ class xmpp(PagePlugin):
cfg.html_root.services.menu.add_item("XMPP", "icon-comment", "/services/xmpp", 40)
self.client_service = service.Service(
- 'xmpp-client', _('Chat Server - client connections'), enabled=True)
+ 'xmpp-client', _('Chat Server - client connections'),
+ is_external=True, enabled=True)
self.server_service = service.Service(
- 'xmpp-server', _('Chat Server - server connections'), enabled=True)
+ 'xmpp-server', _('Chat Server - server connections'),
+ is_external=True, enabled=True)
self.bosh_service = service.Service(
- 'xmpp-bosh', _('Chat Server - web interface'), enabled=True)
-
- # XXX: This is not correct. This essentially triggers firewall
- # to enable XMPP ports. This happen on every start of
- # Plinth. XMPP should be an option to be enabled on Plinth. If
- # and when the user enables the following notifications must
- # sent. If XMPP has be on by default in FreedomBox, then
- # initial setup process that sets up XMPP also must open the
- # firewall ports by default.
- self.client_service.notify_enabled(self, enabled=True)
- self.server_service.notify_enabled(self, enabled=True)
- self.bosh_service.notify_enabled(self, enabled=True)
+ 'xmpp-bosh', _('Chat Server - web interface'), is_external=True,
+ enabled=True)
@cherrypy.expose
@require()
diff --git a/modules/installed/system/firewall.py b/modules/installed/system/firewall.py
index f3faf78ea..885859357 100644
--- a/modules/installed/system/firewall.py
+++ b/modules/installed/system/firewall.py
@@ -77,7 +77,9 @@ or in case of system with systemd 'systemctl start firewalld'
return self.fill_template(title=_("Firewall"), main=main + status)
- enabled_services = self.get_enabled_services()
+ internal_enabled_sevices = self.get_enabled_services(zone='internal')
+ external_enabled_sevices = self.get_enabled_services(zone='external')
+
services_info = ''
for service in service_module.SERVICES.values():
if service.is_enabled():
@@ -89,9 +91,16 @@ or in case of system with systemd 'systemctl start firewalld'
port_info = []
for port in service.ports:
- if port in enabled_services:
+ if port in internal_enabled_sevices and \
+ port in external_enabled_sevices:
text = _('Permitted')
css_class = 'firewall-permitted'
+ elif port in internal_enabled_sevices:
+ text = _('Permitted (internal only)')
+ css_class = 'firewall-permitted'
+ elif port in external_enabled_sevices:
+ text = _('Permitted (external only)')
+ css_class = 'firewall-permitted'
else:
text = _('Blocked')
css_class = 'firewall-blocked'
@@ -133,18 +142,18 @@ a service is automatically disabled in the firewall.'''
output = self._run(['get-status'])
return output.split()[0] == 'running'
- def get_enabled_services(self):
+ def get_enabled_services(self, zone):
"""Return the status of various services currently enabled"""
- output = self._run(['get-enabled-services'])
+ output = self._run(['get-enabled-services', '--zone', zone])
return output.split()
- def add_service(self, port):
+ def add_service(self, port, zone):
"""Enable a service in firewall"""
- self._run(['add-service', port])
+ self._run(['add-service', port, '--zone', zone])
- def remove_service(self, port):
+ def remove_service(self, port, zone):
"""Remove a service in firewall"""
- self._run(['remove-service', port])
+ self._run(['remove-service', port, '--zone', zone])
def on_service_enabled(self, sender, service_id, enabled, **kwargs):
"""
@@ -154,22 +163,38 @@ a service is automatically disabled in the firewall.'''
del sender # Unused
del kwargs # Unused
- enabled_services = self.get_enabled_services()
+ internal_enabled_services = self.get_enabled_services(zone='internal')
+ external_enabled_services = self.get_enabled_services(zone='external')
cfg.log.info('Service enabled - %s, %s' % (service_id, enabled))
- for port in service_module.SERVICES[service_id].ports:
+ service = service_module.SERVICES[service_id]
+ for port in service.ports:
if enabled:
- if port not in enabled_services:
- self.add_service(port)
+ if port not in internal_enabled_services:
+ self.add_service(port, zone='internal')
+
+ if service.is_external and \
+ port not in external_enabled_services:
+ self.add_service(port, zone='external')
else:
- if port in enabled_services:
+ if port in internal_enabled_services:
enabled_services_on_port = [
service_.is_enabled()
for service_ in service_module.SERVICES.values()
if port in service_.ports and
service_id != service_.service_id]
if not any(enabled_services_on_port):
- self.remove_service(port)
+ self.remove_service(port, zone='internal')
+
+ if port in external_enabled_services:
+ enabled_services_on_port = [
+ service_.is_enabled()
+ for service_ in service_module.SERVICES.values()
+ if port in service_.ports and
+ service_id != service_.service_id and
+ service_.is_external]
+ if not any(enabled_services_on_port):
+ self.remove_service(port, zone='external')
@staticmethod
def _run(arguments, superuser=True):
diff --git a/service.py b/service.py
index e310eceea..81ffc3ed5 100644
--- a/service.py
+++ b/service.py
@@ -35,13 +35,15 @@ class Service(object):
for operation.
"""
- def __init__(self, service_id, name, ports=None, enabled=True):
+ def __init__(self, service_id, name, ports=None, is_external=False,
+ enabled=True):
if not ports:
ports = [service_id]
self.service_id = service_id
self.name = name
self.ports = ports
+ self.is_external = is_external
self._enabled = enabled
# Maintain a complete list of services
@@ -65,9 +67,10 @@ class Service(object):
def init():
"""Register some misc. services that don't fit elsewhere"""
- Service('http', _('Web Server'), ['http'], True)
- Service('https', _('Web Server over Secure Socket Layer'),
- ['https'], True)
- Service('ssh', _('Secure Shell (SSH) Server'), ['ssh'], True)
- Service('plinth', _('FreedomBox Web Interface (Plinth)'),
- ['https'], True)
+ Service('http', _('Web Server'), ['http'], is_external=True, enabled=True)
+ Service('https', _('Web Server over Secure Socket Layer'), ['https'],
+ is_external=True, enabled=True)
+ Service('ssh', _('Secure Shell (SSH) Server'), ['ssh'], is_external=True,
+ enabled=True)
+ Service('plinth', _('FreedomBox Web Interface (Plinth)'), ['https'],
+ is_external=True, enabled=True)