Post

Wireless adapters on systemd-nspawn containers

Update 2

15/04/2024: the feature is already available on the latest systemd versions. You can use the Interface= option on the .nspawn configuration file to bind the wireless adapter to the container. I.e.:

1
2
3
4
5
6
7
$ cat /etc/systemd/nspawn/container.nspawn
[Exec]
Boot=true
PrivateUsers=true

[Network]
Interface=wlan0

and it should just work.

Update 1

25/01/2024: it’s going to change with this pull request and should just work out of the box using the Interface= option on the .nspawn configuration file. I will update this post or create a new one when the feature is released.

The problem

The last night I was trying to setup a systemd-nspawn container that will use a wireless adapter to perform some WiFi pentesting. I said to myself, this is going to be easy, I just need to bind the wireless adapter to the container and that’s it. But I was wrong, when I tried to start the container with Interface=wlan0 on my .nspawn configuration file, I got the following error:

1
Failed to move interface wlan0 to namespace: Invalid argument

So, I did a quick search on the internet and I found that this is a known issue. As per Lennart words the problem is (or was):

Last time I looked wifi devices were not compatible with network namespaces in the Linux kernel, and there’s nothing we can do about that in nspawn, it’s a kernel limitation. As soon as the kernel gets fixed in this regard it should start working in nspawn too without further changes.

The solution

A quick read in the comments will drive you to the solution, basically you need to:

  • Get the phy* interface name of your wireless adapter.
  • Get the PID of the init (systemd) of the container.
  • Set the netns of the phy* interface to the PID of the init (systemd) on the container.

Putting all together you will get something like this:

1
2
3
4
5
6
7
8
9
10
# Get the phy* interface name of your wireless adapter
$ iw dev
phy#0
    Interface wlan0
        ifindex 3
        wdev 0x1
        addr 00:11:22:33:44:55
        type managed
        channel 1 (2412 MHz), width: 20 MHz, center1: 2412 MHz
        txpower 20.00 dBm

then the phy* interface name is phy0 - note the #0 part change.

1
2
3
# Get the PID of the init (systemd) on the container
$ machinectl status ContainerName | awk '/Leader:/{print $2}'
1234

then the PID of the init (systemd) on the container is 1234.

1
2
# Set the netns of the phy* interface to the PID of the init (systemd) on the container
$ sudo iw phy phy0 set netns 1234

Now you can get a shell to the systemd-nspawn container and it will have access to the wireless adapter.

1
2
3
4
$ machinectl shell ContainerName
$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DORMANT group default qlen 1000 link/ether 00:11:22:33:44:55 brd ff:ff:ff:ff:ff:ff

and now you can use the wireless adapter on the container as you wish.

References

  • https://github.com/systemd/systemd/issues/7873

The next post will be about how to get container’s GUI apps running on a Wayland session (GNOME) using a nested mutter instance. Stay tuned!

This post is licensed under CC BY 4.0 by the author.