In this tutorial, we'll learn how to use different network interfaces for different processes.
First, we'll learn about the firejail command to run a program and choose a network interface. Then, we'll learn we can also configure a network namespace to force a process to use a specific network interface. To do this, we'll use the ip command with the netns, link, addr, and route subcommands.
2. Introduction to the Problem
Some computers have more than one network interface. For example, we can have a laptop with an Ethernet interface and a WiFi interface, or we can have a server with several Ethernet interfaces.
When a process wants to communicate over the network, the system binds the process to an interface. The system uses the routing table to decide which interface to use. We can see the routing table with the ip route list command.
Let's suppose that there are two rules in the routing table. One rule maps the 10.1.0.0/24 network with the eth0 interface, and the other maps the 10.2.0.0/24 network with the wlan0 interface. Then, if a process wants to connect to IP 10.2.0.15, the system binds the process to the wlan0 interface.
When both interfaces are connected to the same network we can use any interface. So, we may want to choose which interface to use as this can be useful, for instance, to balance the usage of the interfaces.
Some programs provide a way to configure which network interface to use. However, there are programs that don't have that feature.
In this article, we'll assume we have an eth0 interface and a wlan0 interface, and both are connected to the same network.
3. Using the firejail Command
firejail is a security program to isolate a process in its own environment. With the firejail command, we can isolate the network and force a process to use one network interface.
To do this, firejail uses network namespaces. Also, it uses the setuid special file permission. Because of this, we can run firejail as any user.
Some Linux distributions provide the firejail package in their repositories. In that case, we can use the package manager to install it. However, if the package is not available, we can download it from the firejail official website.
After we install firejail, we can use it to run different processes with different network interfaces. For that, we can use the firejail --net=<interface> <program...> command.
Let's run firefox with the eth0 interface:
$ firejail --net=eth0 firefox
Here, we forced firefox to use the eth0 interface.
We can also run the wget command with the wlan0 interface:
$ firejail --net=wlan0 wget http://example.com/file/example.bin
firejail can also change the IP and gateway for the process. We can use the --ip=<ip> and --defaultgw=<gateway> parameters to do that.
4. Using Network Namespaces
In this section, we'll learn about network namespaces so we can choose which network interface a process binds to.
4.1. Method Overview
We can use network namespaces to create a new network configuration with its own interfaces. So, we can configure a network namespace that contains only the interface we want to use. This allows us to run a process inside this network namespace and it'll only see the interface we want.
There are two ways of adding the interface to the network namespace. One way is to move the interface to the network namespace. If we do this, the interface won't be visible outside the namespace. Another way is to create a virtual interface inside the network namespace and link it to the real interface. This way, the interface will still be visible outside the namespace.
We'll use the virtual interface method as this allows us to keep the interface visible to other processes outside the namespace.
There are 3 steps to configure a network namespace, and we have to use the root user. First, we have to create the namespace. Then, we have to create a new interface inside the namespace and link it to the network interface we want to use. Finally, we have to configure the new network interface.
We'll create two namespaces, one named wlanns for the wlan0 interface and another one named ethns for the eth0 interface. This way, we can choose the network interface by running the process in one namespace or the other.
4.2. Configuring the Network Namespaces and Adding the Interfaces
We can use the ip netns add <name> command to create a new namespace. Let's create two new network namespaces, one for the wlan0 interface and one for the eth0 interface:
# ip netns add wlanns
# ip netns add ethns
We can see that we created the wlanns and the ethns network namespaces.
Now, we can add a virtual interface inside each network namespace using the ip link add command:
# ip link add link wlan0 wlan0_ns netns wlanns type ipvlan mode l2
# ip link add link eth0 eth0_ns netns ethns type ipvlan mode l2
As we can see, the full command line is ip link add link <real_interface> <virtual_interface> netns <namespace> type ipvlan mode l2. This command creates a new ipvlan interface called <virtual_interface>. Then it links it to the <real_interface> interface and puts it inside the <namespace> network namespace.
When we don't want to use a network namespace anymore, we can delete it using the ip netns del <namespace> command.
4.3. Configuring the Interfaces
Now, we have to configure the new interfaces. As we'll be configuring interfaces inside namespaces, we can use the -n <namespace> parameter to run ip commands inside the <namespace> network namespace.
To configure the new interfaces we have to do 3 steps. First, we have to set them to the UP state so they become active. Then, we have to configure them with an IP address. Finally, we have to add a default route with our gateway.
We can set the interface to the UP state using the ip link set <interface> up command. We should also configure the loopback device. Let's do it:
# ip -n wlanns link set lo up
# ip -n wlanns link set wlan0_ns up
# ip -n ethns link set lo up
# ip -n ethns link set eth0_ns up
We can see that we run the link set command inside the wlans and ethns namespaces using the -n parameter.
Now, we have to configure the IP and the default route to each interface. We can use the current IPs and gateway from the real interfaces. We can use the ip addr command to see the current IPs. Also, we can use the ip route list command to obtain the current gateway.
Let's use the ip addr add and ip route add commands to configure our new interfaces:
# ip -n wlanns addr add 192.168.0.78/24 dev wlan0_ns
# ip -n wlanns route add default via 192.168.0.1 dev wlan0_ns
# ip -n ethns addr add 192.168.0.81/24 dev eth0_ns
# ip -n ethns route add default via 192.168.0.1 dev eth0_ns
Here, we configured the wlan0_ns interface with IP 192.168.0.78 and the eth0_ns interface with IP 192.168.0.81. Also, we configured both the network namespaces with a default route using the 192.168.0.1 gateway.
If we can't connect to domains inside of the namespace, we can configure the DNS settings for each namespace. To do this, we can write a resolv.conf file inside the /etc/netns/<namespace>/ directory. For instance, the /etc/netns/ethns/resolv.conf file corresponds to the ethns namespace DNS settings.
4.4. Running a Process Inside a Network Namespace
Now that we created the network namespaces and configured the interfaces, we can run a process inside of them.
We can use the ip netns exec <namespace> <program ...> command to run a program inside the <namespace> network namespace. As we created the ethns and wlanns namespaces we can use a different network interface for different processes by choosing either the ethns or the wlanns namespace.
Let's run firefox inside the ethns namespace to use the eth0 interface:
# ip netns exec ethns firefox
This way, the firefox process will use the eth0 interface.
We can also run a different process with the wlan0 interface. Let's run the wget command inside the wlanns namespace:
# ip netns exec wlanns wget http://example.com/file/example.bin
Now, the wget process will use the wlan0 interface to download the file.
As we need to be root to use the ip netns exec command, the process runs as root as well. Moreover, we can run the process as another user using the sudo command with the -u <user> option.
Let's run firefox as the baeldung user inside the ethns network namespace:
# ip netns exec ethns sudo -u baeldung firefox
In this article, we learned how to use different network interfaces for different processes.
First, we learned about the firejail command and how we can use it. Then, we learned we can also configure network namespaces to force a process to use a specific network interface.