Configuring WLAN NAT for lxc

Posted on Wed 22 February 2017 in Sysadmin

After having successfully installed an unprivildged linux container, I wanted to use my WLAN interface for the network but I could not create a bridge due to security restricition of the protocol. So I had to configure NAT over my wireless to make it working. I want to show here the steps to achieve this.

The problem

My first idea was to bridge the WLAN interface to my lxc bridge but this doesn't work:

sudo brctl addif lxcbr0 wlp2s0
can't add wlp2s0 to bridge lxcbr0: Operation not supported

At first glance it might look weird but here is some more detailed explanation:

It's no longer possible to add an interface in the managed mode to a
bridge.  You should run hostapd first to pure the interface to the
master mode.

Bridging doesn't work on the station side anyway because the 802.11
header has three addresses (except when WDS is used) omitting the
address that would be needed for a station to send or receive a packet
on behalf of another system.

-- 
Regards,
Pavel Roskin

I didn't want to use hostap to solve this problem, I choosed the NAT alternative.

Preparing the host system

First you need prepare your host system to activate NAT. We will need to configure a bit the firewal, install iptables if you don't have it already:

sudo xbps-install iptables

Then I activate the NAT at the kernel level where wlp2s0 is the name of my wireless interface:

echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
sudo iptables -t nat -A POSTROUTING -o wlp2s0 -j MASQUERADE

Now you have to set an IP to your bridge so it can communicate, I will use the range 10.0.0/24 and assign the first IP available:

sudo brctl addbr lxcbr0
sudo ifconfig lxcbr0 10.0.0.1/24 up

Now your host system is ready for NATing!

Configuring the container

Now we still will have to configure the newtork within the container. Some would prefer installing a DHCP server on the host but I like setting a static IP to each container, so I know how to reach them.

First you will need to know the IP of your DNS server, that is your router most of the time but to be sure, check the /etc/resolv.conf file of your host, that is 192.168.0.1 for me:

cat /etc/resolv.conf 
# Generated by dhcpcd from wlp2s0.dhcp
# /etc/resolv.conf.head can replace this line
domain local
nameserver 192.168.0.1
# /etc/resolv.conf.tail can replace this line

Now the network configuration is dependent on the distribution you have in your container but the Debian way that also work with Ubuntu is to edit the /etc/network/interfaces file:

lxc-attach -n ubuntu-xenial
root@ubuntu-xenial:/# vim /etc/network/interfaces

Now assign a new IP in the range defined previously, I choosed 10.0.0.100 for this container where the gateway is the IP of your bridge and the name server the one found in /etc/resolv.conf of your host system:

auto eth0
iface eth0 inet static
        address 10.0.0.100
        netmask 255.255.255.0
        gateway 10.0.0.1
        dns-nameservers 192.168.0.1

Now apply the configuration and test with ping:

root@ubuntu-xenial:/# /sbin/ifdown eth0
root@ubuntu-xenial:/# /sbin/ifup eth0
root@ubuntu-xenial:/# ping www.google.com
PING www.google.com (216.58.213.196) 56(84) bytes of data.
64 bytes from ham02s15-in-f196.1e100.net (216.58.213.196): icmp_seq=1 ttl=51 time=38.6 ms
^C
--- www.google.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 38.678/38.678/38.678/0.000 ms

Now you can open an ssh connection to your container from your host:

ssh random@10.0.0.100
random@10.0.0.100's password: 
Welcome to Ubuntu 16.04.2 LTS (GNU/Linux 4.9.11_1 x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
Last login: Wed Feb 22 11:24:13 2017 from 10.0.0.1
$

That was easy!

Start lxc script

Now as my network configuraton has changed a bit, here is how my script to start the container looks like:

#!/bin/sh
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
sudo iptables -t nat -A POSTROUTING -o wlp2s0 -j MASQUERADE
sudo brctl addbr lxcbr0
sudo ifconfig lxcbr0 10.0.0.1/24 up
sudo cgm create all $USER
sudo cgm chown all $USER $(id -u) $(id -g)
cgm movepid all $USER $$
lxc-start -n ubuntu-xenial

Further reading

Some pointers that helped me solving this issue: