Open paralin opened 2 years ago
https://github.com/flatpak/xdg-dbus-proxy/issues/47
This is currently not possible with xdg-dbus-proxy or otherwise. In the issue above:
This is the situation:
I have NetworkManager running on the host system. I have systemd and dbus running in a privileged Docker container. I want nmcli in the container to access the NetworkManager on the host system. However: I also need to be able to access dbus services within the container as well.
The goal is to have requests for NetworkManager be routed to the parent dbus, and requests for anything else sent to the container dbus.
Response:
What you are asking for is combining two "real" buses into one proxied bus, so that clients can connect to the proxied bus, send requests, and have those requests go to one or the other of the "real" buses, depending on the request; for example you might have NetworkManager on the host's "real" system bus, but some other service (let's say systemd) on a different "real" system bus inside your Docker container. Is that right?
I don't think that can actually work in general, because D-Bus isn't designed for that. For example, if you send a request like AddMatch or GetNameOwner to org.freedesktop.DBus, where do we send that - the bus with NetworkManager on it, or the bus with systemd on it? The right answer is "it depends".
[...]
I think the way to achieve your higher-level goal would be to have a content-aware proxy that provides the service side of the NetworkManager interface inside the container (so to other software inside the container, it pretends to be NetworkManager), and then implements that by turning round and connecting as a client to a socket that comes from outside the container (so to software outside the container, it behaves like a NetworkManager client like nmcli).
If your aim is to have a security boundary, so that the NetworkManager client can talk to the host NetworkManager but nothing else, then you might want to use xdg-dbus-proxy as well, to provide a filtered version of the real host system bus inside the container. Like this: [diagram]
The approach I'll try to implement here is as suggested above: creating a program which pretends to be NetworkManager and forwards those requests to the parent system bus. We can still use xdg-dbus-proxy in skiff core to run a filtered version of the host system bus which prevents the container from accessing anything but NetworkManager.
This is not the best, because there are other services that would be good to forward too - like the host systemd (for poweroff / sleep). But it'd be a start.
Forwarding method calls seems to be very straight forward.
The "bridge" connects to both "outside" and "inside" D-Bus. After that it acquires org.freedesktop.NetworkManager
bus name on the "inside". Now every message received on the "inside" just can to be re-send to the "outside". The "bridge" should maintain a map of message cookies and translate back the response messages. For the "outside" it will look like the "bridge" sends all messages.
Bridging signals seems more difficult but I think you can mirror the match rules created on the "inside" and recreate the same rules on the "outside" that captures the NetworkManager signals.
This all is assuming you bridge service on the "outside" to "inside". Bridging from "inside" to "outside" is probably way more difficult.
I am developing my own D-Bus Python library so I have some understanding of the D-Bus.
Bridging signals seems more difficult but I think you can mirror the match rules created on the "inside" and recreate the same rules on the "outside" that captures the NetworkManager signals.
Actually you can just subscribe to all signals emitted by NetworkManager on the "outside" using wildcard match rules and then just emit them back on the "inside". This is less efficient but saves you the trouble of monitoring the match rules.
@igo95862 I looked at doing this in the past and the dbus codebase is so confusing I had a hard time making it happen. Will have another look but let me know if you start a repo somewhere with a prototype and I'll test it out.
dbus codebase is so confusing
D-Bus is a protocol and there are many implementations. I am most familiar with the sd-bus from systemd.
if you start a repo somewhere with a prototype and I'll test it out.
I might try putting together a prototype this weekend. Not sure what to implement it in. My Python library is not well suited for the low level work. I might do some C Glib, C++ or Zig.
@paralin I created an prototype here: https://github.com/igo95862/dbus-forwarding-proxy
It can forward a service between different D-Bus instances.
To build you only need meson, libsystemd and glib.
For example, forwarding NetworkManager from system bus to session bus:
./build/src/dbus-forwarding-proxy --from-dbus-address "unix:path=/run/dbus/system_bus_socket" --service org.freedesktop.NetworkManager --to-dbus-address "$DBUS_SESSION_BUS_ADDRESS"
I tested it a bit with D-Feet and it seems to work.
There is also a --pid
option that will make it switch to the given PID's mount namespace. This can be used with containers or sandboxes.
Only method calls are supported at the moment but I think signals will be easy to implement.
@igo95862 awesome, thanks! I'll give it a try.
https://github.com/flatpak/xdg-dbus-proxy
Use the proxy to forward NetworkManager and other resources from the SkiffOS host system into the dbus in systemd/dbus-enabled Skiff Core containers.