11

I've set up several network namespaces on my Linux system (kernel version 3.10), and now I want to configure each network namespace to have its own DNS settings.

I created resolv.conf files in each /etc/netns/[namespace] directory, and now I want to make my system work in the following way:

In bash command line, whenever I enter the context of a particular network namespace with nsenter --net=/run/netns/[namespace name], I want all processes launched from command line (like nslookup, ping) to run with the DNS settings that I configured with the matching /etc/netns/[namespace name]/resolv.conf.

If I run my commands like this:

 "ip netns exec [namespace name] [command]"

then the DNS settings of the namespace apply.

However, when running the commands without "ip netns exec", the DNS settings are taken from /etc/resolv.conf, even though running "netns get cur" indicates that the context is set to the desired network namespace.

I tried doing mount --bind /etc/netns/[namespace name]/resolv.conf /etc/resolv.conf in the context of the appropriate network namespace, but this applies the mount in the entire system rather then only in the context of that network namespace.

I suspected that using mount namespaces may help, so I tried reading the man page of mount namespaces, however couldn't make anything out of it in the short time that I dedicated to it.

Is there an easy and elegant way to achieve this goal?

Any help/direction toward the solution will be greatly appreciated!

7

Solution

You can use ip netns exec with bash instead of using nsenter, i.e.:

ip netns exec [namespace name] bash

This will allow you to enter an interactive shell session where the namespace-specific network configuration files are automatically bind-mounted to their default (global) locations (without affecting other sessions).

Explanation

The following is taken from the ip netns man page:

For applications that are aware of network namespaces, the convention is to look for global network configuration files first in **/etc/netns/**NAME/ then in /etc/. For example, if you want a different version of /etc/resolv.conf for a network namespace used to isolate your vpn you would name it /etc/netns/myvpn/resolv.conf.

ip netns exec automates handling of this configuration, file convention for network namespace unaware applications, by creating a mount namespace and bind mounting all of the per network namespace configure files into their traditional location in /etc.

Note in particular the distinction between network-namespace aware applications and network-namespace unaware applications.

The nsenter man pages, on the other hand, do not seem to mention this distinction (in particular I searched for the strings "aware", "resolv", ".conf" and "/etc" and found no results). This seems to suggest that the nsenter utility does not perform the same kind of automatic handling of namespace unaware applications.

Additional Comments

In addition to Network Namespaces, you might also want to look at User Namespaces and Mount Namespaces. And if you're going to want further isolation beyond DNS you might also want to consider containerization, e.g. LXC Containers, Docker, or even a full VM.

2
  • 2
    nsenter is the CLI tool to the setns system call. As such, it only does exactly this: joining namespaces. It does not anything to it, like ip netns does, in particular it does not introduce complexity with additional config file locations. Please note that you should always keep the UTS namespace in mind, as it isolates the hostname as well as the domainname.
    – TheDiveO
    Jun 3 '18 at 15:10
  • 2
    I learened so much from this! The most astonishing thing is that there are recent and informative man-pages for ip. I made my piece with not having ip-man pages eons ago.
    – Bananguin
    May 29 '20 at 9:33
6

Just look at what is doing ip netns exec test ... in your situation, using strace.

Excerpt:

# strace  -f ip netns exec test sleep 1 2>&1|egrep '/etc/|clone|mount|unshare'|egrep -vw '/etc/ld.so|access'
unshare(CLONE_NEWNS)                    = 0
mount("", "/", 0x55f2f4c2584f, MS_REC|MS_SLAVE, NULL) = 0
umount2("/sys", MNT_DETACH)             = 0
mount("test", "/sys", "sysfs", 0, NULL) = 0
open("/etc/netns/test", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 5
mount("/etc/netns/test/resolv.conf", "/etc/resolv.conf", 0x55f2f4c2584f, MS_BIND, NULL) = 0

so to reproduce (partially, eg /sys isn't handled here) what ip netns exec test ... is doing:

~# ip netns id

~# head -1 /etc/resolv.conf 
# Generated by NetworkManager

~# nsenter --net=/var/run/netns/test unshare --mount sh -c 'mount --bind /etc/netns/test/resolv.conf /etc/resolv.conf; exec bash'

~# ip netns id
test
~# head -1 /etc/resolv.conf 
# For namespace test
~#

So that's right. nsenter alone isn't enough. unshare has to be used, to change to a newly created mount namespace (basing this new on a copy of the previous one) and alter it, and not just using verbatim an existing one, since there is no existing one yet that fits. That's what is doing the syscall of the same name as is telling strace.

0
1

The first two answers provide good information and answers but I will try to answer from a slightly different angle.

A network namespace gives you a place to put network interfaces, network routing routes and rules, and network filter entries.

A mount namespace gives you a place to put files. These files could be network related, and could be intended to be used in a specific network namespace, but in the end they are just files.

Creating a new network namespace (e.g. with “ip netns add newnetns”) does not automatically give you a new mount namespace.

If you use the “ip netns exec newnetns somecomand” command then you will create a new process (somecommand) using the new network namespace (newnetns that you previously created) and you will also get a new mount namespace created for this process. You will also get certain files bind mounted into that new mount namespace (e.g. /etc/netns/newnetns/resolv.conf onto /etc/resolv.conf). Now when using “ip netns exec” these files are usually network related, like resolv.conf. However, even if these files are network related and you likely created them to use with your new network namespace, they are not part of your new network namespace. When your process (somecommand) terminates, the mount namespace that was created for it will also go away (unless via other means you attached another process to that same mount namespace) but the network namespace will remain.

When you use the nsenter command, it places your command into the network namespace of your choice but nsenter does not create a new mount namespace like “ip netns exec” does.

Worth noting is that “ip netns add newnetns” creates a new network namespace that is basically empty. You have to add interfaces or routes to that new network namespace. “ip netns exec” which puts a process into that network namespace, creates a new mount namespace which is basically a copy of the main mount namespace (so likely showing your main filesystem), with just a few bind mounts added to it.

Also worth noting is that the ip-netns man page mentions the file convention that it will use on behalf of network namespace unaware applications. This may give the impression that there are a whole bunch of network aware applications that use the file convention /etc/netns/nsname/... As far as I’m aware this is not the case. Off hand I can’t think of any other application that uses the files in /etc/netns/nsname/..., but maybe there are.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.