I left Firewall class almost untouched, just renamed it to
SystemConfigFirewall because system-config-firewall is I
think the only service prividing
org.fedoraproject.Config.Firewall interface.
I added new FirewallD class with the same interface as
SystemConfigFirewall so it's transparent to a client.
SystemConfigFirewall works the way that it first discovers what's
allowed in firewall with one call (read()).
And then again with one call (write()) it allows what's necessary.
FirewallD class uses separate call for each service/port query or
modification.
The newly added services are allowed for 60s (could be changed to
whatever value you like).
The code suppose that there's only one active network zone [1] which
should be true under most conditions - what to do otherwise
will be evaluated later.
It works good here with either firewalld or system-config-firewall.
I've had only one problem so far that I would appreciate a help with -
for detailed description see comment in FirewallD.read() function.
[1]
https://fedoraproject.org/wiki/Features/network-zones
---
firewall.py | 160 ++++++++++++++++++++++++++++++++++++++++++++++-------
newprinter.py | 12 ++--
serversettings.py | 6 +-
3 files changed, 150 insertions(+), 28 deletions(-)
diff --git a/firewall.py b/firewall.py
index f344a67..2d2be00 100644
--- a/firewall.py
+++ b/firewall.py
@@ -27,11 +27,132 @@ import dbus
import json
from debug import *
-class Firewall:
- ALLOW_IPP_CLIENT = "--service=ipp-client"
- ALLOW_IPP_SERVER = "--service=ipp"
- ALLOW_SAMBA_CLIENT = "--service=samba-client"
- ALLOW_MDNS = "--service=mdns"
+IPP_CLIENT_SERVICE = "ipp-client"
+IPP_CLIENT_PORT = "631"
+IPP_CLIENT_PROTOCOL = "udp"
+IPP_SERVER_SERVICE = "ipp"
+IPP_SERVER_PORT = "631"
+IPP_SERVER_PROTOCOL = "tcp"
+MDNS_SERVICE = "mdns"
+MDNS_PORT = "5353"
+MDNS_PROTOCOL = "udp"
+SAMBA_CLIENT_SERVICE = "samba-client"
+
+
+class FirewallD:
+ DBUS_INTERFACE = "org.fedoraproject.FirewallD1"
+ DBUS_INTERFACE_ZONE = DBUS_INTERFACE+".zone"
+ DBUS_PATH = "/org/fedoraproject/FirewallD1"
+
+ def __init__ (self):
+ try:
+ bus = dbus.SystemBus ()
+ obj = bus.get_object (self.DBUS_INTERFACE, self.DBUS_PATH)
+ self._firewall = dbus.Interface (obj, self.DBUS_INTERFACE_ZONE)
+ except (dbus.DBusException), e:
+ self._firewall = None
+ return
+
+ debugprint ("Using FirewallD")
+ self._fw_data = []
+ # TODO: fix to allow more than one active zone
+ self._zones=self._get_active_zones()[0]
+ self._timeout=60
+
+ def initialized (self):
+ return self._firewall != None
+
+ def _get_active_zones(self):
+ try:
+ return map (str, self._firewall.getActiveZones())
+ except (dbus.DBusException), e:
+ debugprint ("FirewallD getting active zones failed")
+ return ""
+
+ def _addService(self, service):
+ try:
+ self._firewall.addService (self._zone, service, self._timeout)
+ except (dbus.DBusException), e:
+ debugprint ("FirewallD allowing service %s failed" % service)
+ pass
+
+ def add_service (self, service):
+ self._fw_data.append (service)
+
+ def write (self):
+ map (self._addService, self._fw_data)
+ self._fw_data = []
+
+ def read (self, reply_handler=None, error_handler=None):
+ if reply_handler:
+ # Here I would like to just call the reply_handler() because we
+ # don't need to do anything else here, but if I remove the
+ # getServices() call and directly call reply_handler()
+ # the firewall dialog that the NewPrinterGUI.on_firewall_read()
+ # creates becomes unresponsive.
+
+ #reply_handler (self._fw_data)
+ self._firewall.getServices (self._zone,
+ reply_handler=reply_handler,
+ error_handler=error_handler)
+ return
+
+ def check_ipp_client_allowed (self):
+ try:
+ return (self._firewall.queryService(self._zone,
+ IPP_CLIENT_SERVICE)
+ or self._firewall.queryPort(self._zone,
+ IPP_CLIENT_PORT,
+ IPP_CLIENT_PROTOCOL))
+ except (dbus.DBusException), e:
+ debugprint ("FirewallD query ipp-client service/port failed")
+ return True
+
+ def check_ipp_server_allowed (self):
+ try:
+ return (self._firewall.queryService(self._zone,
+ IPP_SERVER_SERVICE)
+ or self._firewall.queryPort(self._zone,
+ IPP_SERVER_PORT,
+ IPP_SERVER_PROTOCOL))
+ except (dbus.DBusException), e:
+ debugprint ("FirewallD query ipp-server service/port failed")
+ return True
+
+ def check_samba_client_allowed (self):
+ try:
+ return self._firewall.queryService(self._zone,
+ SAMBA_CLIENT_SERVICE)
+ except (dbus.DBusException), e:
+ debugprint ("FirewallD query samba-client service failed")
+ return True
+
+
+ def check_mdns_allowed (self):
+ try:
+ return (self._firewall.queryService(self._zone, MDNS_SERVICE)
+ or self._firewall.queryPort(self._zone, MDNS_PORT,
+ MDNS_PROTOCOL))
+ except (dbus.DBusException), e:
+ debugprint ("FirewallD query mdns service/port failed")
+ return True
+
+
+
+
+class SystemConfigFirewall:
+ DBUS_INTERFACE = "org.fedoraproject.Config.Firewall"
+ DBUS_PATH = "/org/fedoraproject/Config/Firewall"
+
+ def __init__(self):
+ try:
+ bus = dbus.SystemBus ()
+ obj = bus.get_object (self.DBUS_INTERFACE, self.DBUS_PATH)
+ self._firewall = dbus.Interface (obj, self.DBUS_INTERFACE)
+ debugprint ("Using system-config-firewall")
+ except (dbus.DBusException), e:
+ debugprint ("No firewall ")
+ self._firewall = None
def _get_fw_data (self, reply_handler=None, error_handler=None):
try:
@@ -45,12 +166,6 @@ class Firewall:
self._client_reply_handler (self._fw_data)
except AttributeError:
try:
- bus = dbus.SystemBus ()
- obj = bus.get_object ("org.fedoraproject.Config.Firewall",
- "/org/fedoraproject/Config/Firewall")
- iface = dbus.Interface (obj,
- "org.fedoraproject.Config.Firewall")
- self._firewall = iface
if reply_handler:
self._firewall.read (reply_handler=reply_handler,
error_handler=error_handler)
@@ -58,7 +173,7 @@ class Firewall:
p = self._firewall.read ()
self._fw_data = json.loads (p.encode ('utf-8'))
- except (dbus.DBusException, ValueError), e:
+ except (dbus.DBusException, AttributeError, ValueError), e:
self._fw_data = (None, None)
if error_handler:
debugprint ("D-Bus exception examining firewall")
@@ -101,27 +216,30 @@ class Firewall:
isect = set (search).intersection (set (args))
return len (isect) != 0
- def add_rule (self, rule):
+ def add_service (self, service):
try:
(args, filename) = self._fw_data
except AttributeError:
(args, filename) = self._get_fw_data ()
if filename == None: return
- args.append (rule)
+ args.append ("--service=" + service)
self._fw_data = (args, filename)
def check_ipp_client_allowed (self):
- return self._check_any_allowed (set(["--port=631:udp",
- self.ALLOW_IPP_CLIENT]))
+ return self._check_any_allowed (set(["--port=%s:%s" %
+ (IPP_CLIENT_PORT, IPP_CLIENT_PROTOCOL),
+ "--service=" +
IPP_CLIENT_SERVICE]))
def check_ipp_server_allowed (self):
- return self._check_any_allowed (set(["--port=631:tcp",
- self.ALLOW_IPP_SERVER]))
+ return self._check_any_allowed (set(["--port=%s:%s" %
+ (IPP_SERVER_PORT, IPP_SERVER_PROTOCOL),
+ "--service=" +
IPP_SERVER_SERVICE]))
def check_samba_client_allowed (self):
- return self._check_any_allowed (set([self.ALLOW_SAMBA_CLIENT]))
+ return self._check_any_allowed (set(["--service=" +
SAMBA_CLIENT_SERVICE]))
def check_mdns_allowed (self):
- return self._check_any_allowed (set(["--port=5353:udp",
- self.ALLOW_MDNS]))
+ return self._check_any_allowed (set(["--port=%s:%s" %
+ (MDNS_PORT, MDNS_PROTOCOL),
+ "--service=" + MDNS_SERVICE]))
diff --git a/newprinter.py b/newprinter.py
index 595be04..b642910 100644
--- a/newprinter.py
+++ b/newprinter.py
@@ -1618,7 +1618,9 @@ class NewPrinterGUI(GtkGUI):
try:
if (self._host == 'localhost' or
self._host[0] == '/'):
- self.firewall = firewall.Firewall ()
+ self.firewall = firewall.FirewallD ()
+ if not self.firewall.initialized():
+ self.firewall = firewall.SystemConfigFirewall ()
debugprint ("Examining firewall")
self.firewall.read (reply_handler=self.on_firewall_read,
error_handler=lambda x:
@@ -1648,11 +1650,11 @@ class NewPrinterGUI(GtkGUI):
secondary_text += ("- " +
_("Allow all incoming IPP Browse packets")
+
"\n")
- f.add_rule (f.ALLOW_IPP_CLIENT)
+ f.add_service (firewall.IPP_CLIENT_SERVICE)
if not mdns_allowed:
secondary_text += ("- " +
_("Allow all incoming mDNS traffic") +
"\n")
- f.add_rule (f.ALLOW_MDNS)
+ f.add_service (firewall.MDNS_SERVICE)
if not allowed:
debugprint ("Asking for permission to adjust firewall:\n%s" %
@@ -1678,7 +1680,7 @@ class NewPrinterGUI(GtkGUI):
def adjust_firewall_response (self, dialog, response):
dialog.destroy ()
if response == gtk.RESPONSE_YES:
- self.firewall.add_rule (self.firewall.ALLOW_IPP_SERVER)
+ self.firewall.add_service (firewall.IPP_SERVER_SERVICE)
self.firewall.write ()
debugprint ("Fetching devices after firewall dialog response")
@@ -2090,7 +2092,7 @@ class NewPrinterGUI(GtkGUI):
dialog.destroy ()
if response == gtk.RESPONSE_YES:
- f.add_rule (f.ALLOW_SAMBA_CLIENT)
+ f.add_service (firewall.SAMBA_CLIENT_SERVICE)
f.write ()
except (dbus.DBusException, Exception):
nonfatalException ()
diff --git a/serversettings.py b/serversettings.py
index 62d345f..89b725e 100644
--- a/serversettings.py
+++ b/serversettings.py
@@ -526,7 +526,9 @@ class ServerSettings(GtkGUI):
try:
if (self._host == 'localhost' or
self._host[0] == '/'):
- f = firewall.Firewall ()
+ f = firewall.FirewallD ()
+ if not f.initialized():
+ f = firewall.SystemConfigFirewall ()
allowed = f.check_ipp_server_allowed ()
else:
# This is a remote server. Nothing we can do
@@ -549,7 +551,7 @@ class ServerSettings(GtkGUI):
dialog.destroy ()
if response == gtk.RESPONSE_YES:
- f.add_rule (f.ALLOW_IPP_SERVER)
+ f.add_service (fireall.IPP_SERVER_SERVICE)
f.write ()
except (dbus.DBusException, Exception):
nonfatalException ()
--
1.7.7.6