from linux's namespace to the world

Our goal is to send a ping -c 4 www.google.com command from inside a network namespace.

Gimme only the solution!? There it is:

$ sudo ip netns add ns101
$ sudo ip netns
$ sudo ip link add veth-ns101 type veth peer name veth-ns101-br0
$ sudo ip link set veth-ns101 netns ns101
$ sudo ip netns exec ns101 ip address add 192.168.5.3/24 dev veth-ns101
$ sudo ip link add name br0 type bridge
$ sudo ip addr add 192.168.5.4/24 brd + dev br0
$ sudo ip link set veth-ns101-br0 master br0
$ sudo ip link set br0 up
$ sudo ip link set veth-ns101-br0 up
$ sudo ip netns exec ns101 ip link set veth-ns101 up
$ sudo ip netns exec ns101 ip route add default via 192.168.5.4 dev veth-ns101
$ sudo iptables -t nat -A POSTROUTING -s 192.168.5.0/24 -j MASQUERADE
$ sudo sysctl -w net.ipv4.ip_forward=1
$ sudo sh -c 'echo "nameserver 8.8.8.8" > /etc/netns/ns101/resolv.conf'

Going through the solution step-by-step.

# Create the namespace
$ ip netns add ns101

# List namespaces
$ ip netns

# Check the namespace's IP address 
$ ip netns exec ns101 ip address show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

As expected, ns101 have only the loopback interface and with status down. Now let’s create a virtual Ethernet (veth) to connect both ends. But first, what is a veth?

“Veths …can act as tunnels between network namespaces to create a bridge to a physical network device in another namespace, but can also be used as standalone network devices.” - Linux man page

#Create virtual Ethernet devices (veth)
$ sudo ip link add veth-ns101 type veth peer name veth-ns101-br0

$ sudo bridge link show
veth-ns101-br0@veth-ns101: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
veth-ns101@veth-ns101-br0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000

The veth-ns101 will be associated with the ns101 and veth-ns101-br0 with our bridge interface. We don’t have the bridge yet, but will get there soon.

# Set veth-ns101 to ns101
$ sudo ip link set veth-ns101 netns ns101

After listing the devices with $ sudo bridge link show, you should see only:

veth-ns101-br0@veth-ns101: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000

Let’s check if veth-ns101 is present in the ns101 namespace.

$ sudo ip netns exec ns101 ip address show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
27: veth-ns101@if33: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000

Define an IP address for the veth-tjce end of the virtual Ethernet device…

$ sudo ip netns exec ns101 ip address add 192.168.5.3/24 dev veth-ns101
# List ns101 interfaces address
$ sudo ip netns exec ns101 ip address show

Should expect something like:

XX: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
XX: veth-ns101@if32: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 1a:84:d9:fc:16:00 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.5.3/24 scope global veth-ns101
       valid_lft forever preferred_lft forever

veth-ns101 is now set with ip 192.168.5.3

Now we should create the bridge and connect veth-ns101-br0 and set the veth interfaces and bridge to up. Keep in mind that… “A Linux bridge is a kernel module that behaves like a network switch, forwarding packets between interfaces that are connected to it. It’s usually used for forwarding packets on routers, on gateways, or between VMs and network namespaces on a host.” - https://developers.redhat.com/articles/2022/04/06/introduction-linux-bridging-commands-and-features

# Create a bridge
$ sudo ip link add name br0 type bridge

# Define an IP address for the bridge
$ sudo ip addr add 192.168.5.4/24 brd + dev br0

# Connect veth-ns101-br0 to the bridge
$ sudo ip link set veth-ns101-br0 master br0

# Set to up the bridge interface
$ sudo ip link set br0 up

# Set to up the veth-ns101-br0 interface
$ sudo ip link set veth-ns101-br0 up

# Set to up the veth-ns101 up within the namespace
$ sudo ip netns exec ns101 ip link set veth-ns101 up

At this point, we should be able to access ns101 from the default namespace.

ping -c 4 192.168.5.3
PING 192.168.5.3 (192.168.5.3) 56(84) bytes of data.
64 bytes from 192.168.5.3: icmp_seq=1 ttl=64 time=0.039 ms
64 bytes from 192.168.5.3: icmp_seq=2 ttl=64 time=0.054 ms
64 bytes from 192.168.5.3: icmp_seq=3 ttl=64 time=0.054 ms
64 bytes from 192.168.5.3: icmp_seq=4 ttl=64 time=0.046 ms

--- 192.168.5.3 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3089ms
rtt min/avg/max/mdev = 0.039/0.048/0.054/0.006 ms

Now, let’s check connectivity from ns101 to the default namespace:

# Check connection from ns101 -> default namespace
$ sudo ip netns exec ns101 ping -c 4 192.168.5.4
PING 192.168.5.4 (192.168.5.4) 56(84) bytes of data.
64 bytes from 192.168.5.4: icmp_seq=1 ttl=64 time=0.046 ms
64 bytes from 192.168.5.4: icmp_seq=2 ttl=64 time=0.051 ms
64 bytes from 192.168.5.4: icmp_seq=3 ttl=64 time=0.048 ms
64 bytes from 192.168.5.4: icmp_seq=4 ttl=64 time=0.054 ms

--- 192.168.5.4 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3065ms
rtt min/avg/max/mdev = 0.046/0.049/0.054/0.003 ms

Those ns101 have access to the internet?

Well, let’s try it.

# PING from inside ns101 to 8.8.8.8
ip netns exec ns101 ping -c 4 8.8.8.8
ping: connect: Network is unreachable

It looks like that ns101 can’t reach 8.8.8.8. The route table can gives us hint of what is going on…

$ sudo ip netns exec ns101 ip route
192.168.5.0/24 dev veth-ns101 proto kernel scope link src 192.168.5.3 

There is no default gateway set. Thus, ns101 don’t know how to reach any host outside of 192.168.5.0/24. To fix this, lets configure a default gateway for ns101 .

$ sudo ip netns exec ns101 ip route add default via 192.168.5.4 dev veth-ns101

# Check a routes
$ sudo ip netns exec ns101 ip route
default via 192.168.5.4 dev veth-ns101 
192.168.5.0/24 dev veth-ns101 proto kernel scope link src 192.168.5.3 

And let’s try again to reach for 8.8.8.8 within ns101

ip netns exec ns101 ping -c 4 8.8.8.8`
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.

--- 8.8.8.8 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 3062ms

No more Network is unreachable. But no response received?! Why is that?!

That is beacuse of something call NAT, which stands for Network address translation. To solve this problem we have to set on iptable’s nat table to enable NAT for 192.168.5.0/24.

# Mask the source IP addresses of outgoing packets from the 192.168.5.0/24 subnet with the firewall's own IP address
$ sudo iptables -t nat -A POSTROUTING -s 192.168.5.0/24 -j MASQUERADE

And finally, let’s check our ping -c 4 8.8.8.8 from inside ns101 again…

# Check if the ns101 has access to the internet
$ sudo ip netns exec ns101 ping -c 4 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=56 time=72.1 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=56 time=95.0 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=56 time=118 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=56 time=42.9 ms

--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 42.894/81.920/117.759/27.723 ms

Nice, 4 package received. Now the final test…

$ sudo ip netns exec ns101 ping -c 4 www.google.com

Issue with DNS… to fix it, create a resolv.conf file inside the /etc/netns/ns101/resolv.conf with nameserver 8.8.8.8, enable ipv4 forward and redo the test.

$ sudo sh -c 'echo "nameserver 8.8.8.8" > /etc/netns/ns101/resolv.conf'

# Enable IP Forward - Why is that? Visit https://unix.stackexchange.com/a/678361
$ sudo sysctl -w net.ipv4.ip_forward=1

$ sudo ip netns exec ns101 ping -c 4 www.google.com

VoilĂ , finally you can reach a host on the internet through ns101!