Sandboxed network interfaces using unshare

networking
namespaces
linux
Author

Emmanuel Jeandel

Published

January 25, 2023

Unshare is a linux command that is used to execute commands (and shells) in new namespaces. This can be useful to isolate this command from the main namespaces. Among others, namespaces you can isolate are the PID namespace, the user namespace, and the network namespace.

What is especially nice is that you can change the network namespace without being root!

The command to do that is:

unshare -rn

This executes a new shell by default.

As ifconfig or ip addr will show, this new shell will live in a new namespace that doesn’t contain any of your usual network interfaces. It contains the interface lo, but be aware that the interface is down by default.

You will notice that you are root in the new shell. I don’t know what is happening exactly behind the scenes, but, while you seem to be root in this new shell, you are still the same user as usual for the host machine.

What can you do with this network namespace that contains no interface ? One use might be to execute commands that you don’t trust.

In this first post, I will explain how you can use these network namespaces to simulate a network of 2 machines:

In practice, you will have two shells opened (possibly in two terminals), one corresponding to each machine. The filesystem of both machines is still your nominal filesystem, which is usually useful for experiments.

Here is how to do it, first open two shells/terminals and type the command

unshare -rn

unshare creates two namespaces, one for each shell, but these namespaces are anonymous. To reference an anonymous namespace, you can reference it by the PID of one application in that namespace. Therefore we will execute the command

echo $$

in both shells to know the PID of the bash process (or your favorite shell, if it is not bash)

In the following, FIRST_PID is the PID of the first bash process, and SECOND_PID the PID of the second bash process.

Now in the first shell, type

ip link add veth00 netns FIRST_PID type veth peer veth11 netns SECOND_PID

This will create an interface veth00 in the first namespace (the first shell) that is linked to the interface veth11 in the second namespace.

Now you can add IP to these interfaces, put them up, and do some networking!

firstshell# ip addr add 10.42.0.2/24 dev veth00
firstshell# ip link set veth00 up

secondshell# ip addr add 10.42.0.3/24 dev veth11
secondshell# ip link set veth11 up

And that’s it! You can test everything is working as it should by pinging the machines. You can also try to see the traffic using wireshark, remember to launch wireshark from inside one of the two shells, and to use the interfaces veth00 and veth11.

Remarks

  • If you try to ping 10.42.0.2 from the firstshell, this will not work, because this implicitely uses the lo interface that is down. If you want to be able to ping yourself, you can do ip link set lo up.

  • The interface is only visible in the shell if they share the same namespace. When the previous command is typed, veth00 is visible in the first shell, but veth11 is visible only in the second shell.

  • You can try the command

ip link add veth00 netns FIRST_PID type veth peer veth11 netns 1

to link the device veth00 to the namespace of the process of PID 1. What is that process ? Well it’s init on your host machine, so this way you are making a link between your sandboxed namespace and your real namespace. However, you have now created a device veth11 in your real namespace but you cannot add an IP address to this one, because you’re not root on this namespace.

  • It won’t surprise anyone that most of these features are very useful to make containers. The important thing here is that we can do this in user mode. This does not provide a real sandboxing, but it is very useful if you just want to test some small networking scripts as a user which is not root.