Logo

Using Linux Network Namespaces for per processes routing

Linux Linux Desktop Namespaces Networking Routing Sysadmin

7 minutes

The use case for this article may seem a bit strange in year 2013 but I swear it’s real. I have a (relatively) fast connection but I have a traffic cap on it and a (really) slow one which is flat. I would like to run not interactive task like “aptitude safe-upgrade” on the slow one but the bulk of my connections should go through the fast one. The work is done on a Debian Wheezy system, check that the “ip” command is not too old and lacks network namespace support.

Linux namespaces are a cool feature that permit process groups to have a limited view of system resource. See the superb LWN article for more information. In this article we will use network namespaces which permits different process groups to have a different view of the networking system. Processes in a network namespace cannot see the physical network adapter but only a virtual one. We can create 2 of them as the endpoints of a pipe to make the processes in a network namespace speak with the outer net. For this we will use the simplest approach, a bridge. Other, more complicate, setups like NAT are of course possible.

First of all lets define some convenience variables:

BASE_IP=10.0.10.253
FAST_GW=10.0.10.58
NETMASK=255.255.255.0
SLOW_IP=10.0.10.149
SLOW_GW=10.0.10.57

These define the physical IP address of my machine, the fast connection gateway, the netmask of my setup, the IP that will be seen by processes in the network container and the gatway for the slow network.

Next we have to create the network namespace. Its name is slow for obvious reasons:

ip netns add slow

and the virtual ethernets that act as the endpoints for the pipe from it to the “real world”:

ip link add veth0 type veth peer name veth1
ifconfig veth0 0.0.0.0 up
ip link set veth1 netns slow

we have to unconfigure the physical network card because it will be part of the bridge:

ifdown eth0
ifconfig eth0 0.0.0.0 up

and then we bridge it to one endpoint of the pipe to the network namespace:

brctl addbr br0
brctl addif br0 eth0 veth0

we reassign the base ip to the bridge interface so we can continue working as before for processes not in network namespace:

ifconfig br0 $BASE_IP netmask $NETMASK up
route add default gw $FAST_GW

the configuration of the host is finished, now we have to turn our attention to what happens in the network namespace. To execute a process there we have to use the command ip netns exec [namespace] [command]. Here we setup the IP address of the interface in the namespace and define the default route pointing to the slow gateway:

ip netns exec slow ifconfig veth1 $SLOW_IP netmask $NETMASK up
ip netns exec slow route add default gw $SLOW_GW

and voilà, we can now run our favorite long-running network command in the newly created namespace:

ip netns exec slow aptitude safe-upgrade

we can also start a shell there, so everything we will do there will be routed to the slow gateway. We can also relogin as a non privileged user (ip nets commands need root privileges):

ip netns exec slow bash
ip netns exec slow su - chri

Linux namespaces are a very powerful tool. Their primary use are containers but they are useful in many other situations such as this.

 

Comments #

  • gag on 2014-01-27 07:50:45 +0100

Hi,
nice tute . but there is a problem when i create a namespace and then logout and log in again in linux kernal.there is no namespace there and namespace automatically deleted. how i can solve this problem please help.thanks

  • Christian Pellegrin on 2014-01-31 10:45:45 +0100

Yes, the namespace configuration, like all other ones, must be reissued on every restart. Where it’s done depends on distribution. Under Debian Wheezy (the one I use) you have to configure /etc/network/interfaces. Another, easier but not so clean, solution is to run the commands from /etc/rc.local.

  • gag on 2014-02-05 07:12:55 +0100

thanks for reply. i got it. hi everything is ok before line
ip netns exec slow aptitude safe-upgrade
but when i run above command there is unknown host error . then i try to ping google.com in new network namespace again same error. then i try ping 8.8.8.8 its working. also in local namespace ping google.com is working but not in new network namespace . please can u tell me why this and how i can resolve this.?

  • gag on 2014-02-05 07:24:56 +0100

can u give me some code to write in /etc/network/interfaces or rc.local
thanks

  • Christian Pellegrin on 2014-02-06 07:54:00 +0100

If you just created a newtork namespace (and not others) the /etc/resolv.conf and /etc/gai.conf file should be the same so the resolver library should work. Which distribution are you using? For /etc/rc.local it’s easy: just copy the command you use there.

  • gag on 2014-02-06 09:29:18 +0100

thank you . my dns resolving problem solved after setting same nameserver in /etc/gai.conf as in /etc/resolv.conf.

what its mean “created a network namespace (not others) here what the mean of “not other.”

i am using ubuntu 13 in virtualbox . i think when we create a namespace there is /var/run/netns/ file is created using command “ip netns add ”
but on reboot the ubuntu /var/run/netns directory automatically deleted . now i want to know which command i copy in rc.local

thanks

  • gag on 2014-02-06 11:32:06 +0100

hi
after these commands
ip netns exec slow bash
ip netns exec slow su – chri

we will enter in the slow network namespace .then how we can exit from this i mean how we can again enter in default namespace

  • Christian Pellegrin on 2014-02-09 08:43:34 +0100

I mean that you can have also file-system namespaces for example. Perfect, in newer Linux distros gai is used in place of older resolver. To exit a namespace just exit the shell.

  • gag on 2014-02-10 07:40:49 +0100

can i use mount namespace and pid namespace along with network namespace such that files in new mount namespace only accessible through network namespace . if yes how i create a mount and pid namespace and how to use in network namespace?
thanks

  • Christian Pellegrin on 2014-02-10 08:14:28 +0100

Yes, you can do with the setns tool but I don’t know if it makes sense. Perhaps if you need PID and FS isolation too it’s better to go for a fully fledged solution like LXC

  • Hubert on 2014-02-20 15:14:47 +0100

Many thanks for the infos..

One question though: Is it also possible to force a process to use a specific name server using namespaces, or is that more difficult?

  • Christian Pellegrin on 2014-02-21 22:31:57 +0100

The resolver is configured by using /etc/resolv.conf or /etc/gai.conf so a file-system namespace can be used to present different /etc/ directories to a process.

  • Christian Pellegrin on 2014-02-22 07:30:21 +0100

Another clever trick to use a different DNS is to use NAT to rewrite the destination/source address only for DNS queries. Let’s say that in the global net namespace I use Google DNS 8.8.8.8 but in my specific net namespace I want to be a good Italian citizen and let Telecom Italia DNS 85.37.17.51 decide what is good and what is evil. Now I can just do:
`
OLD_IP=8.8.8.8
NEW_IP=85.37.17.51

iptables -t nat -A OUTPUT -p tcp -d $OLD_IP -j DNAT --dport 53 --to-destination $NEW_IP
iptables -t nat -A INPUT -p tcp -s $OLD_IP --sport 53 -j SNAT --to-source $NEW_IP
iptables -t nat -A OUTPUT -p udp -d $OLD_IP -j DNAT --dport 53 --to-destination $NEW_IP
iptables -t nat -A INPUT -p udp -s $OLD_IP --sport 53 -j SNAT --to-source $NEW_IP
` Now you can check that uploaded.net resolves to 127.0.0.1 for example by using wireshark with a filter like `(tcp.port == 53 || udp.port==53) && ip.addr == 10.0.10.149` on the physical `eth0` interface, assumed that the IP for your net namespace is `10.0.10.149`. In this way you don’t have to mess with different configuration files.

  • Federico Pellegrin on 2014-02-22 07:52:09 +0100

In quite old iptables version there was also the –cmd-owner flag to apply a rule to a process (per name) that could suit also the question. But this was removed at some point in 2.6 kernels. There is still –pid-owner that could fit with a little of scripting.

Otherwise there is still the possibility to filter on UID/GID (with –uid-owner and -gid-owner).

They are all related to the owner module (so use -m owner)

Ciao!