Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

skiff/core: bridge dbus to host system for some services like NetworkManager #211

Open
paralin opened this issue May 31, 2022 · 7 comments

Comments

@paralin
Copy link
Collaborator

paralin commented May 31, 2022

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.

@paralin paralin self-assigned this May 31, 2022
@paralin paralin changed the title core: add xdg-dbus-proxy skiff/core: bridge dbus to host system for some services like NetworkManager Feb 23, 2023
@paralin
Copy link
Collaborator Author

paralin commented Feb 23, 2023

flatpak/xdg-dbus-proxy#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]

Conclusion

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.

@igo95862
Copy link

igo95862 commented Apr 25, 2024

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.

@igo95862
Copy link

igo95862 commented Apr 25, 2024

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.

@paralin
Copy link
Collaborator Author

paralin commented Apr 25, 2024

@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.

@igo95862
Copy link

igo95862 commented Apr 25, 2024

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.

@igo95862
Copy link

igo95862 commented Apr 27, 2024

@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.

@paralin
Copy link
Collaborator Author

paralin commented Apr 27, 2024

@igo95862 awesome, thanks! I'll give it a try.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants