Monday, April 3, 2017

How to run Firefox in a separate network name space

In this post I'll explain how to run Firefox (or any other application) in a separate network name space. If you wonder why would you do that, here are some reasons:
  1. You connect to a VPN and want a single application to connect via VPN. All the other applications should access network as usual.
  2. You want to know what network resources specific application does access. For example, there is a JavaScript application that runs within the Web browser and you want to monitor it on a network level.
  3. You want to temporarily use another IP address, but in the same time keep the existing network configuration because some applications use it and they wouldn't react well on the change.
  4. You have alternative connection to the Internet (e.g. one via wired interface, and another via LTE) and you want some applications to use LTE, default being wired interface. This is actually variation of the cases 1 and 3, but obviously it's not the same.
Probably there are some other reasons, too, but I think this is enough to persuade you into advantages of using network namespaces on Linux. And note that you can run two instances of Firefox in the same time. One "normal" in the "normal" network namespace, and another one in new and potentially restricted network namespace. More on that later in the post.

So, here is how to create new network name space with network interface(s). Note that there are several different cases, depending on how you connect to the Internet and what you want to achieve. So, there will be several subcases. But first, create a new network name space using the following command (as a root user):
# ip netns add <NSNAME>
NSNAME will be the name of the network name space. You should use something short and meaningful, i.e. something that will associate you to what the network namespace is used for. You can check that there is a network name space using the following command:
# ip netns list
From this point on we have two subcases:
  • You are connected using wired Ethernet interface and you can attach new machines to the Ethernet network.
  • You are connected to the Internet using wireless Ethernet interface or you are connected to the wired Ethernet interface and are not allowed to connect new machines.
All those cases are described in the following subsections.

Wired Ethernet interface

This is the easiest case, and there are several options you can use. We'll use macvlan type of the interface that will create a clone of an existing wired Ethernet interface which will appear on the physical network with its own parameters. This is, in effect, like attaching a new host on the local network. Note that if you are not allowed to connect devices to the network, you should use routing method described for wireless interface.

First step is to create new interface:
# ip link add link <ETHIF> name <IFNAME> type macvlan
The parameters are: ETHIF is your existing Ethernet interface, while IFNAME is a new interface that will be created. You should then move the interface into the target network namespace (we assume here that you want to move it to NSNAME):
# ip link set <IFNAME> netns <NSNAME>
and then you have to activate it:
# ip netns exec <NSNAME> ip link set <IFNAME> up
note that the activation has to be done using "ip netns exec" since to access network interface you have to swich to the network namespace where the interface is! What is left is to assign it an IP address. This can be done statically or via DHCP.

Now that the network part is ready, skip to the section Starting Firefox.

Wireless LAN

In case you are connected to a wireless LAN, then macvlan link type will not work, so another mechanism is necessary. There are two options, bridging and routing. The problem with bridging is that you have to turn off wireless interface before enslaving it into a bridge. That creates two problems. The first one is that all current TCP connections will break, and the second is that it doesn't play nicely with NetworkManager and similar software. Thus, I'll describe routing case.

First, create pair of virtual Ethernet interfaces like this:
ip link add type veth
This will create two new interfaces veth0 and veth1. Those interfaces are actually two ends of a single link. We'll move one interface into another network namespace:
ip link set veth1 netns <NSNAME>
Next we'll configure interfaces with IP addresses. I'll use 10.255.255.1/24 for the interface that's left in the main network namespace (veth0) and 10.255.255.2/24 for the interface in the NSNAME network name space (veth1):
# ip addr add 10.255.255.1/24 dev veth0
# ip link set dev veth0 up
# ip netns exec <NSNAME> ip addr add 10.255.255.2/24 dev veth1
# ip netns exec <NSNAME> ip link set dev veth1 up
# ip netns exex <NSNAME> ip ro add default via 10.255.255.1
we also need to configure NAT because the network 10.255.255.0/24 is only used for the communication of two network namespaces and it should not go outside the host computer:
# iptables -A POSTROUTING -t nat -o wlp3s0 -s 10.255.255.2 -j MASQUERADE
you should change wlp3s0 with the name of your wireless interface. You should take note of two things in case it doesn't work:
  1. Forwarding has to be enabled. This is achieved/checked via sysctl /proc/sys/net/ipv4/ip_forward (it should contain 1).
  2. Maybe your host has firewall that blocks traffic. To check if that's the problem, temporarily disable firewall and try again. Note that disabling a firewall will most likely remove iptables rule you added so you'll have to add it again.

Starting Firefox

Now, when you handled creating the interface within the new network name space, to start Firefox (or any other application) in it, first you should switch into new network name space. Do this in the following way:
# ip netns exec <NSNAME> bash
Note that it is important to do it that way in order to preserve environmental variables, i.e. if you do "su -" or something else, you'll reset environment and you won't be able to start graphical applications. After you got bash shell as a root, switch again to a "normal" user:
su <userid>
again, it is very important to preserve network namespace, so you have to use command su as shown. Obviously, substitute userid with the user ID logged into graphical interface. Next, you should start Firefox:
$ firefox &
In case you already have running instance of Firefox that, for whatever reason, you don't wont to stop then you can start a new instance like this:
$ firefox -P -no-remote&
This will start new instance even though there is a running Firefox proces (-no-remote) and present you with a dialog box to choose a profile to run to. You can not use existing profile so it means that you have to create a new one specially for this purpose. The drawback is that your bookmarks, cookies and other thing won't be visible in a new instance. 

8 comments:

Unknown said...

Hi,
Great reading. I was very positive surprised to see your name Stjepan.
It reminded me of great times at FER when I did a Linux seminar in your group. :)

Best wishes!

Joni said...

Hello was wondering why dns leaks on ubuntu 17.04 // the hardcoded namespace name-servers are ignored and only the host one is used.

very strange

callmejoe said...

this is great. i'm running a VPN client on my desktop and generally want all internet traffic going through it. some websites refuse to work though and i dont like turning off the vpn for this. i just start a new browser in the separate namespace now. thanks!

one thing. does this mean any command running now is run with root privileges? and if so, any security issues with that?

Stjepan Groš (sgros) said...

@callmejoe

As I wrote in the post, before running firefox (or any other user process after setting up name space) you should switch to some normal user. Running everything as a root user, especially such a complex piece of software as Firefox, is a huge security risk! So, don't do that!

callmejoe said...

oh i definitely am switching using su. i thought maybe since bash was started as root then maybe the root privileges carried to the user.

thanks for the reply on an old post

Unknown said...

Hello,
praising God today for finding this! I already use namespaces for some 2 years, for simulating different LAN hosts behind VM router sites, all from single Linux VM host, and had just recently, by accident using Firefox with setuid ip cmd, which I did for my conveniecne. Anyhow coming back to labs after time, I can't get Firefox running becuase of that setuid reasons.. ending in doubt how in the past I managed to run it in namespace.
Now this article sheds a complete new light into what that "pipe" word in stop disclaimer by GTK+ means, it's right that own bash level with ordinary user. Got that!
And to run same profile of Firefox, I just re-use same "firefox &" and it opens new windows.

Unknown said...

Hello,
praising God today for finding this! I already use namespaces for some 2 years, for simulating different LAN hosts behind VM router sites, all from single Linux VM host, and had just recently, by accident using Firefox with setuid ip cmd, which I did for my conveniecne. Anyhow coming back to labs after time, I can't get Firefox running becuase of that setuid reasons.. ending in doubt how in the past I managed to run it in namespace.
Now this article sheds a complete new light into what that "pipe" word in stop disclaimer by GTK+ means, it's right that own bash level with ordinary user. Got that..
And to run same profile of Firefox, I just re-use same "firefox &" and it opens new windows. However, if run from 2 namespaces, I only communicate using the first, already open. Then your "-P -no-remote" setting does the trick. Have you some idea on how new Firefox instance could be run separarely from existing, without using different profiles?

Thank you.
PEter

ster said...
This comment has been removed by the author.

About Me

scientist, consultant, security specialist, networking guy, system administrator, philosopher ;)

Blog Archive