I'm attempting to control firewalld
via the Python dbus
module.
I'd like to add an ip address to the trusted zone for both my current runtime as well as my permanent configuration.
Here's the documentation for firewalld
's dbus interface:
http://manpages.ubuntu.com/manpages/wily/man5/firewalld.dbus.5.html
What works: The runtime configuration
I'm able to add it to the runtime configuration just fine with this:
def trustIP(ip):
''' firewalld must already be running '''
from dbus import SystemBus
bus = SystemBus()
runtimeProxy = bus.get_object('org.fedoraproject.FirewallD1',
'/org/fedoraproject/FirewallD1')
runtimeProxy.addSource('trusted', ip)
Pretty simple.
What doesn't work: The permanent configuration
Adding it to the permanent configuration has proved to be more difficult. Here's what I've tried so far interactively:
>>> from dbus import SystemBus
>>> bus = SystemBus()
# First I need to find out which object is for the trusted zone...
>>> config = bus.get_object('org.fedoraproject.FirewallD1',
'/org/fedoraproject/FirewallD1/config')
>>> config.getZoneByName('trusted')
dbus.ObjectPath('/org/fedoraproject/FirewallD1/config/zone/7')
>>> permanentProxy = bus.get_object('org.fedoraproject.FirewallD1',
'/org/fedoraproject/FirewallD1/config/zone/7')
# A quick check to make sure I have the right object:
>>> permanentProxy.getShort()
dbus.String(u'Trusted')
# Exactly what I expected, so move on and...
>>> permanentProxy.addSource('aaa.xxx.yyy.zzz') # Actual ip removed...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python2.7/site-packages/dbus/proxies.py", line 145, in __call__
**keywords)
File "/usr/lib64/python2.7/site-packages/dbus/connection.py", line 651, in call_blocking
message, timeout)
dbus.exceptions.DBusException:
org.freedesktop.DBus.Python.dbus.exceptions.DBusException:
dbus_to_python() takes exactly 1 argument (2 given)
I also tried checking permanentProxy.getDescription()
, which returned the description as it should have, and I tried permanentProxy.setDescription('test')
which failed with the exact same stack trace as permanentProxy.addSource('aaa.xxx.yyy.zzz')
.
I would jump to the conclusion that the bug lies in the python dbus
module and assume it somehow doesn't handle arguments properly, except for the fact that runtimeProxy.addSource('trusted', ip)
involved two arguments and works perfectly. config.getZoneByName('trusted')
even has the same signature as permanentProxy.addSource('aaa.xxx.yyy.zzz')`, exactly one string, and works perfectly.
So maybe there's something weird I'm missing? But I don't know what that would be...
More stuff I tried without success
I considered the possibility that maybe addSource
is supposed to be called without the string argument at all and maybe curries somehow or something, so I tried this:
>>> permanentProxy.addSource()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python2.7/site-packages/dbus/proxies.py", line 145, in __call__
**keywords)
File "/usr/lib64/python2.7/site-packages/dbus/connection.py", line 651, in call_blocking
message, timeout)
dbus.exceptions.DBusException: org.freedesktop.DBus.Python.TypeError: Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/slip/dbus/service.py", line 123, in reply_handler
result = method(self, *p, **k)
TypeError: addSource() takes at least 2 arguments (2 given)
This is just even weirder now... I have one Traceback within another traceback insisting that I need to pass in at least 2 arguments, but also saying I gave it two arguments (and I actually only gave it one, so how'd it come up with two anyways?)
A few more things I tried without success:
>>> permanentProxy.addSource(dbus_interface='org.fedoraproject.FirewallD1.config.zone')
ERROR:dbus.connection:Unable to set arguments () according to signature u's': <type 'exceptions.TypeError'>: More items found in D-Bus signature than in Python arguments
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python2.7/site-packages/dbus/proxies.py", line 145, in __call__
**keywords)
File "/usr/lib64/python2.7/site-packages/dbus/connection.py", line 641, in call_blocking
message.append(signature=signature, *args)
TypeError: More items found in D-Bus signature than in Python arguments
>>> permanentProxy.addSource('aaa.xxx.yyy.zzz', dbus_interface='org.fedoraproject.FirewallD1.config.zone')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python2.7/site-packages/dbus/proxies.py", line 145, in __call__
**keywords)
File "/usr/lib64/python2.7/site-packages/dbus/connection.py", line 651, in call_blocking
message, timeout)
dbus.exceptions.DBusException:
org.freedesktop.DBus.Python.dbus.exceptions.DBusException:
dbus_to_python() takes exactly 1 argument (2 given)
>>> from dbus import Interface
>>> Interface(permanentProxy, 'org.fedoraproject.FirewallD1.config.zone').addSource('aaa.xxx.yyy.zzz')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python2.7/site-packages/dbus/proxies.py", line 145, in __call__
**keywords)
File "/usr/lib64/python2.7/site-packages/dbus/connection.py", line 651, in call_blocking
message, timeout)
dbus.exceptions.DBusException:
org.freedesktop.DBus.Python.dbus.exceptions.DBusException:
dbus_to_python() takes exactly 1 argument (2 given)
Gah!
This really seems like a bug in dbus
... somehow it's initially resolving addSource
incorrectly and thinking that it needs fewer arguments, but if you give it fewer arguments like it wants, it'll pass that erroneous check, and then it'll properly resolve and fail because your arguments don't match it.
That's my theory anyways. Is someone seeing something I'm not? Is there some way I can work around this bug, if there really is one? IE... is there some kind of internal method I can use on dbus that will force it to call the proper method?
The following works for me:
At this point, if I look in
/etc/firewalld/zones/trusted.xml
, I can see that the source address has been added as expected:...indicating that I have successfully changed the persistent configuration.
The above also works if I use a literal path in the second
get_object
call, instead of the return value fromconfig.getZoneByName
.For what it's worth, I'm running:
UPDATE
You're not seeing anything newer because you're on CentOS, rather than Fedora. It looks like the easiest way of solving this particular task may be to use the
firewall
python module that ships with FirewallD. The following works for me on CentOS 7:ANOTHER UPDATE
Browsing through the source to the
firewall.client
module, you can do this via straight dbus like this:This also works fine under CentOS...but you're much better off using the
firewall
module.