How to isolate app‘s network activity using netns and virtual router
There are a few scenarios when the network isolation can be useful. First, it allows to listen single appications for their network activity. Second, applications can be routed in a specific way, that doesn’t affect the whole system. And third, not covered in this guide, network namespaces can be used to create isolated virtual networks.
Applications in a network namespace will see only their own set of network adapters. They will have their own routing tables as well. With this things, we can control the applications network activity with ease. For example, we can route some applications traffic via VPN, while the others will continue to use the default routing settings.
In order to setup the routing we need the following things:
- Virtual router. It can be anything linux-based. I prefer virtualized pfsense.
- A network namespace. It would be used to launch applications inside it.
- A pair of virtual adapters. They would be used to connect the host with the network namespace. Remember, the network namespace is isolated by its own.
- A routing table. It would be used to route namespace traffic in a different way.
- A few ip/iptables rules. They would be used to make the things work together. They would be simple, I promise.
Virtual router / gateway
For the simplest case you can use basic linux machine with ip forwarding enabled. More complex solutions can include transparent VPN routing and some sort of fail-tolerance options. I found pfsense virtual machine useful for this kind of things. But basically, all you need is a gateway address. It would be used to route all the traffic from the network namespace.
We have no network namespaces from the start:
ip netns ls
Let’s create a new namespace
ip netns add ns1
Now we need to connect the network namespace with the host. We can do this by using a pair of virtual adapters. All the data sent to one adapter would be transfered to another. Let’s create
ip link add veth1a type veth peer name veth1b
You can check both adapters with
ip addr command. They are currently presented in the default network namespace.
Next we move
veth1b adapter to the
ip link set veth1b netns ns1
For this moment “physical” links are set, but both interfaces have no IP addresses. Let’s assign one to each. We will use
192.168.60.0/24 subnet for this example:
Assign address to
ip addr add 192.168.60.1/24 dev veth1a
ip link set veth1a up
Assign address to
ip netns exec ns1 ip addr add 192.168.60.100/24 dev veth1b
ip netns exec ns1 ip link set veth1b up
(optional) We can also enable localhost interface for
ip netns exec ns1 ip link set lo up
Add default route for
ns1 namespace, so all the traffic inside can be routed:
ip netns exec ns1 ip route add default via 192.168.60.1
At this point we can ping both adapters from the corresponding sides:
ip netns exec ns1 ping 192.168.60.1
In order to separate
ns1 traffic from the global routing scheme we need an additional routing table. To create the new one:
echo "1 tns1" >> /etc/iproute2/rt_tables
Then we pass all the traffic from
192.168.60.0/24 subnet to it:
ip rule add from 192.168.60.0/24 table tns1
192.168.56.5 as a default gateway for
ip route add default via 192.168.56.5 table tns1
192.168.60.1 as a gateway for internal
ip route add 192.168.60.0/24 via 192.168.60.1 table tns1
Bringing the things together
The configuration part is done. The last two things we need is to enable linux routing between the interfaces (they are disabled by default). We also need a NAT server to forward
veth1 traffic via the
vboxnet0 interface. Luckly, it’s already included in a linux kernel and only a rule is required.
Enable ip forwarding between the interfaces, so
veth1a interface traffic can be routed to
echo 1 > /proc/sys/net/ipv4/ip_forward
Enable masquerade. Basically it allows the hosts from
192.168.60.0/24 subnet to use
vboxnet0 interface as gateway. It doesn’t say how the traffic should be routed (we did it a few steps before in a Routing table part), it just allows to transparently connect the subnet to another interface via NAT.
iptables -tnat -A POSTROUTING -s 192.168.60.0/24 -o vboxnet0 -j MASQUERADE
To launch an application in the
ns1 namespace the following command is used:
ip netns exec ns1 <app>
For example, you can run a
bash and to play with
ip addr or
ip netns exec ns1 bash
Namespace applications are launched as root by default. To avoid this, you can launch them as
ip netns exec sudo -u user firefox
(optional) You can add the line to
visudo to allow regular users to use
ip netns exec command without password.
user ALL=NOPASSWD: /usr/bin/ip netns exec ns1 sudo -u user *
… and then to launch an application from user account with sudo:
sudo ip netns exec ns1 sudo -u user firefox
Note though, that the inner sudo are used to restrict access to root account. It can be ommited if not required.
Inspecting namespace traffic is simple. Just listen the
tcpdump -i veth1a