dbus_to_python() takes exactly 1 argument?

2019-03-02 15:52发布

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?

1条回答
孤傲高冷的网名
2楼-- · 2019-03-02 16:22

The following works for me:

>>> import dbus
>>> bus = dbus.SystemBus()
>>> config = bus.get_object('org.fedoraproject.FirewallD1',
...                            '/org/fedoraproject/FirewallD1/config')
>>> path = config.getZoneByName('trusted')
>>> zone = bus.get_object('org.fedoraproject.FirewallD1', path)
>>> zone.addSource('192.168.1.0/24')

At this point, if I look in /etc/firewalld/zones/trusted.xml, I can see that the source address has been added as expected:

<?xml version="1.0" encoding="utf-8"?>
<zone target="ACCEPT">
  <short>Trusted</short>
  <description>All network connections are accepted.</description>
  <interface name="docker0"/>
  <interface name="virbr0"/>
  <source address="192.168.1.0/24"/>
</zone>

...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 from config.getZoneByName.

For what it's worth, I'm running:

  • Fedora 23
  • firewalld-0.3.14.2-4.fc23.noarch
  • dbus-1.10.6-1.fc23.x86_64
  • dbus-python-1.2.0-12.fc23.x86_64

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:

>>> from firewall.client import *
>>> client = FirewallClient()
>>> zone = client.config().getZoneByName('public')
>>> settings = zone.getSettings()
>>> settings.addSource('192.168.1.0/24')
>>> zone.update(settings)

ANOTHER UPDATE

Browsing through the source to the firewall.client module, you can do this via straight dbus like this:

>>> zone = bus.get_object('org.fedoraproject.FirewallD1', path)
>>> settings = zone.getSettings()
>>> settings[11].append('192.168.20.0/24')
>>> zone.update(settings)

This also works fine under CentOS...but you're much better off using the firewall module.

查看更多
登录 后发表回答