Network namespaces

Tags: networking, linux,

Added: 2024-10-05T00:00

Network namespaces

One feature of Linux that isn't widely known is the ability to have separate network namespaces in a single Linux instance. This enables segregation of network stacks, which can be very useful for testing and running programs without impacting your main network stack.

Here is a very simple example to show it in action.

# ip netns add NEWNS
# ip netns exec NEWNS bash
# ifconfig -a
lo: flags=8<LOOPBACK>  mtu 65536
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
# ping 127.0.0.1
ping: connect: Network is unreachable


As you can see from this output above, we create a new namespace (NEWNS), and then run a bash shell inside it. The bash shell is started inside the NEWNS namespace, which has no networking configured at all - there are no IP addresses assigned, no devices (other than a loopback device that's not up), and no routes added at all. We're unable to ping 127.0.0.1 (which exists in the main namespace). Any network applications we start (webserver, etc) will be bound to the namespace's network stack and won't be accessible from outside the network namespace. This provides a nice way to test network applications without affecting your main network stack.

VPNs


A more useful example could be the following. You have a VPN (OpenVPN, Wireguard, etc) and you want to use it without affecting the networking on your main machine. The following script will create a new network namespace and start a Wireguard VPN inside it. It assumes you have a working Wireguard setup already.

Run it as your standard user.

NSNAME=wireguard
CONF=/etc/wireguard/wg0.conf

# Grab the IPs from the config file for later
IPV4=$(sudo grep Address ${CONF} | cut -d "=" -f 2 | cut -d "," -f 1)
IPV6=$(sudo grep Address ${CONF} | cut -d "=" -f 2 | cut -d "," -f 2)

# Set up DNS resolution for the namespace
sudo mkdir -p /etc/netns/${NSNAME}
sudo bash -c "echo nameserver 8.8.8.8 > /etc/netns/${NSNAME}/resolv.conf"

# Create the namespace
sudo ip netns add ${NSNAME}

# Bind Wireguard to the new namespace
sudo ip link add wg0 type wireguard
sudo wg setconf wg0 /etc/wireguard/wg0.conf
sudo ip link set wg0 netns ${NSNAME}

# Add the IPs and routes
sudo ip -n ${NSNAME} addr add ${IPV4} dev wg0
sudo ip -n ${NSNAME} addr add ${IPV6} dev wg0
sudo ip -n ${NSNAME} link set wg0 up
sudo ip -n ${NSNAME} route add default dev wg0

# Drop the user into a bash shell in the new namespace
echo Starting bash in the ${NSNAME} namespace
sudo -E ip netns exec ${NSNAME} sudo -E -u \#$(id -u) -g \#$(id -g) bash

After this script has run (assuming no errors), you should be left in a bash shell that only has network access via the VPN.
Add a comment

Your IP:
Please enter 8943779 here: