Showing posts with label network namespaces. Show all posts
Showing posts with label network namespaces. Show all posts

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. 

Wednesday, March 16, 2016

Network namespaces and NetworkManager

This post documents a process to implement support for network namespaces in the NetworkManager. The code described in the post can be found on GitHub. While my personal motivation to add namespace support to NetworkManager was to be able to add support for provisioning domains as specified by IETF MIF WG, it also brings benefits to existing users by allowing isolation of different applications into different network namespaces. The best example is a VPN connection isolation. When network namespaces are used then certain applications can be started in namespace in which only network connectivity is via VPN. Those applications can access VPN resources while all the other applications, that are in different network namespaces, will not see VPN connection and thus couldn't use them. The additional benefit would be from using multiple connections, as described by MIF Architecture RFC.

Note that after I started to work on this, Thomas Haller implemented basic support for namespaces in NetworkManager that was a bit different in some implementation details from mine.

The idea


The intention of implementing support for network namespaces was to allow applications to be isolated so that they use specific network connections. Network namespaces in Linux kernel have some properties that anyone that wants to use them must be aware of. This is documented in a separate post.

So, an application can not be moved between different network namespace by some other application, i.e. only application itself can change network namespaces, and only if it has appropriate permissions.

So, the idea is the following one. Application is started in some network namespace. This can be done easily (e.g. see 'ip netns exec' command). Then, this network namespace is manipulated by either the application itself - it is aware of NM's support for network namespaces, or by third party application (that application could be nmcli). The manipulation means that requests are sent to NetworkManager via D-Bus to make changes to network namespace. The changes can be activation and deactivation of certain connections. NetworkManager, based on those requests and on specifics of connections and devices those connections are bound to, determines what to do. For example, it can create virtual device in the network namespace, or can move physical device. Basically, this part isn't important to the application itself, the only thing that is important is that the application is assigned requested connections.

Implementation


The following changes were made to NetworkManager in order to introduce support for network namespaces:

  1. Created new object NMNetnsController whose purpose is to allow management of all network namespaces controlled by NetworkManager. Via the interface org.freedesktop.NetworkManager.NetworkNamespacesController it is possible to create a new network namespace, or to remove the existing one. It is also possible to obtain a list of existing network namespaces.
     
  2. Created new object NMNetns that represents a single network namespace. So, when new network namespace is created a new object NMNetns is created and exposed on D-Bus. This object allows manipulation with network namespace via the interface org.freedesktop.NetworkManager.NetNsInstance. So, it is possible to get a list of all devices within the network namespace, take certain device from some other network namespace and to activate some connection.
     
  3. NMSettings is now singleton object. This wasn't so significant change because there was also one object of this type before, but now it is more explicitly exposed as such.
     
  4. NMPlatform, NMDefaultRouteManager and NMRouteManager aren't singleton objects any more. They are now instantiated for each new network namespace that is created.


VPN isolation


VPN isolation was done as a first user of network namespaces implementation. It was easier then other connections because the assumption was that VPN connection should live only in single network namespace and it should be the only available connection.

At the beginning, there was doubt on where to place the knowledge of network namespace and two places were candidates, in NMActiveConnection and NMVPNConnection classes. NMActiveConnection is actually a base class of NMVPNConnection class. The modification of NMVPNConnection approach is better for the following reason because the idea was to introduce new configuration parameter in the configuration file of a VPN connection that will specify that isolation is necessary and also some additional behaviors:
  • netns-isolate

    Boolean parameter (yes/no) which defines weather VPN connection should be isolated within a network namespace or not. For backwards compatibility reasons
     
  • netns-persistent

    Should network namespace be persistant (yes) or not (no). Persistant namespace will be retained when VPN connection is terminated, while non-persistant will be removed.
     
  • netns-name

    Network namespace name. Special value is uuid which means connection's UUID should be used, also name is special value that requests connection's name to be used. Finally, any other string is taken as-is and used as a network namespace name.
     
  • netns-timeout

    How much time to wait (in milliseconds) for device to appear in target namespace.
Basically, the implementation is such that when device appears in root network namespace it is taken from there (using TakeDevice method, but called directly instead via D-Bus).  When device appears in the target network namespace network parameters are assigned to the interface. This was tested with OpenVPN type of VPN.

The implementation has two problems. First, the case of VPN connections that don't create virtual devices but instead just modify packet processing rules in the Linux kernel (i.e. XFRM). Secondly, hostname and name resolution parameters aren't assigned because the infrastructure is lacking in that respect.

Conclusion


The initial goal of having network namespaces support in NetworkManager was achieved. There are functionalities missing like isolation of any connection, hostname handling and DNS resolution handling. Those are things that will have to be resolved in the future.

About Me

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

Blog Archive