Merge: Sunil's firewall branch (follow up commits).

This commit is contained in:
Nick Daly 2014-04-28 19:59:06 -05:00
commit bf3286b736
9 changed files with 168 additions and 71 deletions

View File

@ -22,8 +22,6 @@ Configuration helper for Plinth firewall inteface
""" """
import argparse import argparse
import os
import re
import subprocess import subprocess
@ -37,18 +35,31 @@ def parse_arguments():
help='Get whether firewalld is installed') help='Get whether firewalld is installed')
# Get status # 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 # 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 a service
add_service = subparsers.add_parser('add-service', help='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('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 a service status
remove_service = subparsers.add_parser('remove-service', help='Remove a service') remove_service = subparsers.add_parser('remove-service',
remove_service.add_argument('service', help='Name of the service to remove') 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() return parser.parse_args()
@ -66,21 +77,26 @@ def subcommand_get_status(_):
subprocess.call(['firewall-cmd', '--state']) subprocess.call(['firewall-cmd', '--state'])
def subcommand_get_enabled_services(_): def subcommand_get_enabled_services(arguments):
"""Print the status of variours services""" """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): def subcommand_add_service(arguments):
"""Permit a service in the firewall""" """Permit a service in the firewall"""
subprocess.call(['firewall-cmd', '--add-service', arguments.service]) subprocess.call(['firewall-cmd', '--zone', arguments.zone, '--add-service',
subprocess.call(['firewall-cmd', '--permanent', '--add-service', arguments.service]) arguments.service])
subprocess.call(['firewall-cmd', '--zone', arguments.zone, '--permanent',
'--add-service', arguments.service])
def subcommand_remove_service(arguments): def subcommand_remove_service(arguments):
"""Block a service in the firewall""" """Block a service in the firewall"""
subprocess.call(['firewall-cmd', '--remove-service', arguments.service]) subprocess.call(['firewall-cmd', '--zone', arguments.zone,
subprocess.call(['firewall-cmd', '--permanent', '--remove-service', arguments.service]) '--remove-service', arguments.service])
subprocess.call(['firewall-cmd', '--zone', arguments.zone, '--permanent',
'--remove-service', arguments.service])
def main(): def main():

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>Privoxy - A Privacy Enhancing Proxy Server</short>
<description>Privoxy is a web proxy for enhancing privacy by filtering web page content, managing cookies, controlling access, removing ads, banners, pop-ups and other obnoxious Internet junk. It does not cache web content. Enable this if you run Privoxy and would like to configure your web browser to browse the Internet via Privoxy.</description>
<port protocol="tcp" port="8118"/>
</service>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>Tor - SOCKS Proxy</short>
<description>Tor enables online anonymity and censorship resistance by directing Internet traffic through a network of relays. It conceals user's location from anyone conducting network surveillance and traffic analysis. A user wishing to use Tor for anonymity can configure a program such as a web browser to direct traffic to a Tor client using its SOCKS proxy port. Enable this if you run Tor and would like to configure your web browser or other programs to channel their traffic through the Tor SOCKS proxy port. It is recommended that you make this service available only for your computer or your internal networks.</description>
<port protocol="tcp" port="9050"/>
</service>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<service> <service>
<short>XMPP (Jabber) server</short> <short>XMPP (Jabber) server</short>
<description>Extensible Messaging and Presence Protocol (XMPP) server connection protocols allows multiple XMPP (Jabber) servers to work in a fedrated fashion. Users on one server will be able to see the presence of and communicate with users on another servers. Enable this if you run an XMPP (Jabber) server and you wish users on your server to communicate with users on other XMPP servers.</description> <description>Extensible Messaging and Presence Protocol (XMPP) server connection protocols allows multiple XMPP (Jabber) servers to work in a federated fashion. Users on one server will be able to see the presence of and communicate with users on another servers. Enable this if you run an XMPP (Jabber) server and you wish users on your server to communicate with users on other XMPP servers.</description>
<port protocol="tcp" port="5269"/> <port protocol="tcp" port="5269"/>
</service> </service>

View File

@ -1,48 +1,97 @@
#!/bin/sh #!/bin/sh
# Setup firewall rules for all the enabled services # Enable tracing to see the commands in
# /var/log/freedombox-first-run.log
set -x
# Ideally all non essential services are enabled from Plinth # Setup interfaces into appropriate zones. XXX: This is ideally done
# which automatically takes care of enabling appropirate firewall # by network configuration as network configuration tool/scripts have
# ports. This file is used then for essential services and services # better idea of what the interfaces are. There should also be a UI in
# that are not yet configurable from Plinth. # Plinth to classify each interface as external or internal.
# If more than one interfaces is available, assume eth0 is external
# and rest are internal interfaces.
INTERFACES=$(interface-detect | grep wired | grep -v lo | cut -f1 -d,)
NO_OF_INTERFACES=$(echo $INTERFACES | wc --words)
if [ $NO_OF_INTERFACES -gt '1' ]
then
for INTERFACE in $INTERFACES
do
if [ $INTERFACE = 'eth0' ]
then
ZONE='external'
else
ZONE='internal'
fi
firewall-cmd --zone=$ZONE --permanent --add-interface=$INTERFACE
done
fi
# If only one interface is available, assume it to be internal so that
# services are available on this only possible interface. This means
# that all services which are meant to available only internally will
# be available externally if the interface is publicly accessible.
# XXX: To avoid this, FreedomBox should configure at least two
# interfaces. If only one network hardware device is available, an
# alias such as 'eth0:1' could be created and can act as internal
# interface.
if [ $NO_OF_INTERFACES -eq '1' ]
then
firewall-cmd --zone=internal --permanent --add-interface="$INTERFACES"
fi
# 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) # 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) # 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 # Tor
firewall-cmd --permanent --add-port=9050/tcp firewall-cmd --zone=internal --permanent --add-service=tor-socks
# NTP # NTP
firewall-cmd --permanent --add-service=ntp firewall-cmd --zone=internal --permanent --add-service=ntp
# DNS # DNS
firewall-cmd --permanent --add-service=dns firewall-cmd --zone=internal --permanent --add-service=dns
# mDNS # mDNS
firewall-cmd --permanent --add-service=mdns firewall-cmd --zone=internal --permanent --add-service=mdns
# DHCP # DHCP
firewall-cmd --permanent --add-service=dhcp firewall-cmd --zone=internal --permanent --add-service=dhcp
# Bootp Server and Client (not enabled) # Bootp Server and Client (not enabled)
#firewall-cmd --permanent --add-port=67/tcp #firewall-cmd --zone=internal --permanent --add-port=67/tcp
#firewall-cmd --permanent --add-port=67/udp #firewall-cmd --zone=internal --permanent --add-port=67/udp
#firewall-cmd --permanent --add-port=68/tcp #firewall-cmd --zone=internal --permanent --add-port=68/tcp
#firewall-cmd --permanent --add-port=68/udp #firewall-cmd --zone=internal --permanent --add-port=68/udp
# LDAP (not enabled) # LDAP (not enabled)
#firewall-cmd --permanent --add-service=ldap #firewall-cmd --zone=internal --permanent --add-service=ldap
#firewall-cmd --permanent --add-service=ldaps #firewall-cmd --zone=internal --permanent --add-service=ldaps
# OpenVPN (not enabled) # 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 # Privoxy
firewall-cmd --permanent --add-port=8118/tcp firewall-cmd --zone=internal --permanent --add-service=privoxy
# Obfsproxy # XMPP
firewall-cmd --permanent --add-port=40202/tcp 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

View File

@ -17,7 +17,7 @@ class Owncloud(PagePlugin, FormPlugin):
cfg.html_root.apps.menu.add_item("Owncloud", "icon-picture", "/apps/owncloud", 35) cfg.html_root.apps.menu.add_item("Owncloud", "icon-picture", "/apps/owncloud", 35)
self.service = service.Service('owncloud', _('ownCloud'), self.service = service.Service('owncloud', _('ownCloud'),
['http', 'https'], ['http', 'https'], is_external=True,
enabled=self.is_enabled) enabled=self.is_enabled)
def is_enabled(self): def is_enabled(self):

View File

@ -17,22 +17,14 @@ class xmpp(PagePlugin):
cfg.html_root.services.menu.add_item("XMPP", "icon-comment", "/services/xmpp", 40) cfg.html_root.services.menu.add_item("XMPP", "icon-comment", "/services/xmpp", 40)
self.client_service = service.Service( 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( 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( self.bosh_service = service.Service(
'xmpp-bosh', _('Chat Server - web interface'), enabled=True) 'xmpp-bosh', _('Chat Server - web interface'), is_external=True,
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)
@cherrypy.expose @cherrypy.expose
@require() @require()

View File

@ -77,7 +77,9 @@ or in case of system with systemd 'systemctl start firewalld'</p>
return self.fill_template(title=_("Firewall"), main=main + status) 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 = '<ul>' services_info = '<ul>'
for service in service_module.SERVICES.values(): for service in service_module.SERVICES.values():
if service.is_enabled(): if service.is_enabled():
@ -89,9 +91,16 @@ or in case of system with systemd 'systemctl start firewalld'</p>
port_info = [] port_info = []
for port in service.ports: for port in service.ports:
if port in enabled_services: if port in internal_enabled_sevices and \
port in external_enabled_sevices:
text = _('Permitted') text = _('Permitted')
css_class = 'firewall-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: else:
text = _('Blocked') text = _('Blocked')
css_class = 'firewall-blocked' css_class = 'firewall-blocked'
@ -133,18 +142,18 @@ a service is automatically disabled in the firewall.</em></p>'''
output = self._run(['get-status']) output = self._run(['get-status'])
return output.split()[0] == 'running' return output.split()[0] == 'running'
def get_enabled_services(self): def get_enabled_services(self, zone):
"""Return the status of various services currently enabled""" """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() return output.split()
def add_service(self, port): def add_service(self, port, zone):
"""Enable a service in firewall""" """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""" """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): def on_service_enabled(self, sender, service_id, enabled, **kwargs):
""" """
@ -154,22 +163,38 @@ a service is automatically disabled in the firewall.</em></p>'''
del sender # Unused del sender # Unused
del kwargs # 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)) 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 enabled:
if port not in enabled_services: if port not in internal_enabled_services:
self.add_service(port) self.add_service(port, zone='internal')
if service.is_external and \
port not in external_enabled_services:
self.add_service(port, zone='external')
else: else:
if port in enabled_services: if port in internal_enabled_services:
enabled_services_on_port = [ enabled_services_on_port = [
service_.is_enabled() service_.is_enabled()
for service_ in service_module.SERVICES.values() for service_ in service_module.SERVICES.values()
if port in service_.ports and if port in service_.ports and
service_id != service_.service_id] service_id != service_.service_id]
if not any(enabled_services_on_port): 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 @staticmethod
def _run(arguments, superuser=True): def _run(arguments, superuser=True):

View File

@ -35,13 +35,15 @@ class Service(object):
for operation. 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: if not ports:
ports = [service_id] ports = [service_id]
self.service_id = service_id self.service_id = service_id
self.name = name self.name = name
self.ports = ports self.ports = ports
self.is_external = is_external
self._enabled = enabled self._enabled = enabled
# Maintain a complete list of services # Maintain a complete list of services
@ -65,9 +67,10 @@ class Service(object):
def init(): def init():
"""Register some misc. services that don't fit elsewhere""" """Register some misc. services that don't fit elsewhere"""
Service('http', _('Web Server'), ['http'], True) Service('http', _('Web Server'), ['http'], is_external=True, enabled=True)
Service('https', _('Web Server over Secure Socket Layer'), Service('https', _('Web Server over Secure Socket Layer'), ['https'],
['https'], True) is_external=True, enabled=True)
Service('ssh', _('Secure Shell (SSH) Server'), ['ssh'], True) Service('ssh', _('Secure Shell (SSH) Server'), ['ssh'], is_external=True,
Service('plinth', _('FreedomBox Web Interface (Plinth)'), enabled=True)
['https'], True) Service('plinth', _('FreedomBox Web Interface (Plinth)'), ['https'],
is_external=True, enabled=True)