LXC Containerized DNS-DHCP Configurations (Ubuntu dnsmasq bind9)

Summary

I wanted to get this written down in a blog so I'm doing a short WIP post that I will expand later more fully.

I am doing work to move the dynamic DNS-DHCP services for the Orabuntu-LXC project into an LXC container so that installing Orabuntu-LXC does not affect any current bind9 (named) configuration files on the Ubuntu bare-metal host. Ubuntu desktop uses dnsmasq for DNS resolution out-of-the-box. Server installations of Ubuntu, however, would be more likely to have bind9 (named) deployments and so the original design of Orabuntu-LXC to make updates to the bare-metal host DNS and DHCP configuration files was always one of the worst design element of Orabuntu-LXC and I've had it on the agenda for some time to move the DNS-DHCP services for Orabuntu-LXC into an LXC container that gets deployed when Orabuntu-LXC is installed.

This post is on a specific problem; in fact, it was the last main problem holding back the finalization of this DNS-DHCP revised design and incorporation into the Orabuntu-LXC software. The /etc/resolv.conf of the bare-metai host had the "nameserver 127.0.1.1" cast in concrete in Ubuntu 16.04, and by "concrete" I mean that resetting it to another value was proving more difficult than previous Ubuntu versions.

Since I am not using the /etc/network/interfaces file at all in this work, setting dns-nameservers there to get /etc/resolv.conf to update was not very feasible. Also, the usual tricks using /etc/dhcp/dhclient.conf were also not working. And in any case, my goal all along in the Orabuntu-LXC project has been to make minimal changes to the Ubuntu desktop. For example, the OpenvSwitch interfaces in Orabuntu-LXC are not directly attached to any physical interfaces; the WAN is established using iptables rules and routing instead, rather than clobbering a physical interface with an OpenvSwitch. The whole idea of the project has been that Orabuntu-LXC would be a pure add-on tool that leaves the Ubuntu Desktop configurations almost totally unchanged.

Solution

So a couple of years ago I faced a similar issue and did not remember that I had already posted around this same topic then. The solution was gleaned from a post that Sokratis Galliatis had written here and I attributed the solution for the Orabuntu-LXC work on this to his blog post. That work was documented at my blog post here.

I had been trying for (yes I admit it) several hours to find a way to have the /etc/resolv.conf on the Ubuntu desktop bare-metal host get updated with the DNS nameserver IP of the DNS DHCP LXC container but I was asking myself why I would want to do that in the first place. Firstly, I didn't like the idea of changing the /etc/resolv.conf on the bare-metal Ubuntu host at all, because this goes against the guiding principle of Orabuntu-LXC that it should be a pure add-on and not a sea-change requiring changes to the host configurations. Secondly, It was proving nearly impossible to use any of the old tricks I had used on previous versions of Ubuntu to accomplish this.

So here's the solution that was referenced. Basically, there is a file where dnsmasq (Ubuntu's default DNS solution) is notified that certain networks should not be resolved by dnsmasq, and furthermore, (this is the great part) by listing the IP and related information of the desired nameservers that should be used instead in that dnsmasq file, the lookups will be routed automatically by dnsmasq to those other nameservers. Here is that file with the nameservers that are the LXC container DNS-DHCP ip adddresses.

oracle@u1604:~$ cat /etc/NetworkManager/dnsmasq.d/local

server=/orabuntu-lxc.com/10.207.39.2

server=/39.207.10.in-addr.arpa/10.207.39.2

server=/consultingcommandos.us/10.207.29.2

server=/29.207.10.in-addr.arpa/10.207.29.2

oracle@u1604:~$

In this file are provided the forward and reverse lookup zones and the IP addresses of the nameservers that support those zones. And that's it. Once this is in, the lookups for anything on those networks get forwarded "onto a different track" to the appropriate nameserver (the LXC contaienr) and are resolved by the non-dnsmasq nameserver(s). Here's a couple of examples.

oracle@u1604:~$ nslookup u1604

Server: 127.0.1.1

Address: 127.0.1.1#53

Name: u1604.orabuntu-lxc.com

Address: 10.207.39.1

oracle@u1604:~$ nslookup stlnsa

Server: 127.0.1.1

Address: 127.0.1.1#53

Name: stlnsa.orabuntu-lxc.com

Address: 10.207.39.2

oracle@u1604:~$ nslookup 10.207.39.2

Server: 127.0.1.1

Address: 127.0.1.1#53

2.39.207.10.in-addr.arpa name = stlnsa.orabuntu-lxc.com.

oracle@u1604:~$ nslookup 10.207.39.1

Server: 127.0.1.1

Address: 127.0.1.1#53

1.39.207.10.in-addr.arpa name = u1604.orabuntu-lxc.com.

oracle@u1604:~$

Output from netstat confirms that there are no bind9 nameservers running on the bare metal Ubuntu host as shown below. However, ssh into the DNS-DHCP Linux container and sure enough there are the nameservers in the netstat output which are providing the resolution for these addresses even though these nameservers are not in /etc/resolv.conf on the Ubuntu bare-metal host. Neat!

oracle@u1604:~$ sudo netstat -tulnp | grep 53 <-- Ubuntu bare-metal host

[sudo] password for oracle

tcp 0 0 10.0.3.1:53 0.0.0.0:* LISTEN 20605/dnsmasq

tcp 0 0 127.0.1.1:53 0.0.0.0:* LISTEN 2366/dnsmasq

tcp6 0 0 fe80::e411:a4ff:fe9a:53 :::* LISTEN 20605/dnsmasq

udp 0 0 10.0.3.1:53 0.0.0.0:* 20605/dnsmasq

udp 0 0 127.0.1.1:53 0.0.0.0:* 2366/dnsmasq

udp 0 0 0.0.0.0:5353 0.0.0.0:* 999/avahi-daemon: r

udp6 0 0 fe80::e411:a4ff:fe9a:53 :::* 20605/dnsmasq

udp6 0 0 :::5353 :::* 999/avahi-daemon: r

oracle@u1604:~$ ssh ubuntu@stlnsa

ubuntu@stlnsa's password:

Welcome to Ubuntu 16.04.1 LTS (GNU/Linux 4.4.0-43-generic x86_64)

* Documentation: https://help.ubuntu.com

* Management: https://landscape.canonical.com

* Support: https://ubuntu.com/advantage

Last login: Wed Oct 19 23:26:11 2016 from 10.207.39.1

ubuntu@stlnsa:~$ sudo netstat -tulnp | grep 53 <-- LXC DNS-DHCP container

[sudo] password for ubuntu:

tcp 0 0 10.207.29.2:53 0.0.0.0:* LISTEN 188/named

tcp 0 0 10.207.39.2:53 0.0.0.0:* LISTEN 188/named

tcp 0 0 127.0.0.1:953 0.0.0.0:* LISTEN 188/named

tcp6 0 0 :::53 :::* LISTEN 188/named

tcp6 0 0 ::1:953 :::* LISTEN 188/named

udp 0 0 10.207.29.2:53 0.0.0.0:* 188/named

udp 0 0 10.207.39.2:53 0.0.0.0:* 188/named

udp6 0 0 :::53 :::* 188/named

ubuntu@stlnsa:~$

The solution can also be verified by stopping DNS services in the container and then trying to resolve the container from the bare-metal Ubuntu host (fails) as expected as shown below.

ubuntu@stlnsa:~$ sudo service bind9 status <-- bind9 DNS running in the LXC container

â—Ź bind9.service - BIND Domain Name Server

Loaded: loaded (/lib/systemd/system/bind9.service; enabled; vendor preset: enabled)

Drop-In: /run/systemd/generator/bind9.service.d

└─50-insserv.conf-$named.conf

Active: active (running) since Wed 2016-10-19 23:24:34 UTC; 34min ago

Docs: man:named(8)

Main PID: 188 (named)

CGroup: /lxc/stlnsa/system.slice/bind9.service

└─188 /usr/sbin/named -f -u bind

Oct 19 23:48:49 stlnsa named[188]: connection refused resolving 'ns2.google.com/AAAA/IN': 127.0.1.1#53

Oct 19 23:49:47 stlnsa named[188]: connection refused resolving 'quora-prod-tch-vpc-1136165707.us-east-1.elb.amazonaws.com/A/IN': 127.0.1.1#53

Oct 19 23:50:09 stlnsa named[188]: connection refused resolving 'play.google.com/A/IN': 127.0.1.1#53

Oct 19 23:50:09 stlnsa named[188]: connection refused resolving 'play.l.google.com/A/IN': 127.0.1.1#53

Oct 19 23:50:37 stlnsa named[188]: connection refused resolving 'browserchannel-docs.l.google.com/A/IN': 127.0.1.1#53

Oct 19 23:55:13 stlnsa named[188]: connection refused resolving 'play.google.com/A/IN': 127.0.1.1#53

Oct 19 23:55:13 stlnsa named[188]: connection refused resolving 'play.l.google.com/A/IN': 127.0.1.1#53

Oct 19 23:55:37 stlnsa named[188]: connection refused resolving 'browserchannel-docs.l.google.com!/A/IN': 127.0.1.1#53

Oct 19 23:56:29 stlnsa named[188]: connection refused resolving 'quora-prod-tch-vpc-1136165707.us-east-1.elb.amazonaws.com/A/IN': 127.0.1.1#53

Oct 19 23:57:19 stlnsa named[188]: connection refused resolving 'www3.l.google.com/A/IN': 127.0.1.1#53

ubuntu@stlnsa:~$ sudo service bind9 stop <-- bind9 DNS stopped in the LXC container

ubuntu@stlnsa:~$ exit <-- logout of the container

logout

Connection to stlnsa closed.

oracle@u1604:~$ ssh ubuntu@stlnsa <-- of course cannot resolve the DNS container name anymore!

ssh: Could not resolve hostname stlnsa: Name or service not known

oracle@u1604:~$ cat /etc/resolv.conf <-- prove /etc/resolv.conf has not changed

# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)

# DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN

nameserver 127.0.1.1

search orabuntu-lxc.com consultingcommandos.us

oracle@u1604:~$ ssh ubuntu@10.207.39.2 <-- ssh via ip address still works of course...

ubuntu@10.207.39.2's password:

Welcome to Ubuntu 16.04.1 LTS (GNU/Linux 4.4.0-43-generic x86_64)

* Documentation: https://help.ubuntu.com

* Management: https://landscape.canonical.com

* Support: https://ubuntu.com/advantage

Last login: Wed Oct 19 23:53:24 2016 from 10.207.39.1

ubuntu@stlnsa:~$ sudo service bind9 start <-- logged back into LXC container and startup the bind9 DNS service

[sudo] password for ubuntu:

ubuntu@stlnsa:~$ sudo service bind9 status <-- verify bind9 status is good...

â—Ź bind9.service - BIND Domain Name Server

Loaded: loaded (/lib/systemd/system/bind9.service; enabled; vendor preset: enabled)

Drop-In: /run/systemd/generator/bind9.service.d

└─50-insserv.conf-$named.conf

Active: active (running) since Wed 2016-10-19 23:59:33 UTC; 3s ago

Docs: man:named(8)

Process: 326 ExecStop=/usr/sbin/rndc stop (code=exited, status=0/SUCCESS)

Main PID: 369 (named)

CGroup: /lxc/stlnsa/system.slice/bind9.service

└─369 /usr/sbin/named -f -u bind

Oct 19 23:59:33 stlnsa named[369]: zone 31.172.in-addr.arpa/IN: loaded serial 1

Oct 19 23:59:33 stlnsa named[369]: zone 17.172.in-addr.arpa/IN: loaded serial 1

Oct 19 23:59:33 stlnsa named[369]: zone 24.172.in-addr.arpa/IN: loaded serial 1

Oct 19 23:59:33 stlnsa named[369]: zone 168.192.in-addr.arpa/IN: loaded serial 1

Oct 19 23:59:33 stlnsa named[369]: zone 255.in-addr.arpa/IN: loaded serial 1

Oct 19 23:59:33 stlnsa named[369]: zone orabuntu-lxc.com/IN: loaded serial 1512181493

Oct 19 23:59:33 stlnsa named[369]: zone consultingcommandos.us/IN: loaded serial 1512181464

Oct 19 23:59:33 stlnsa named[369]: zone localhost/IN: loaded serial 2

Oct 19 23:59:33 stlnsa named[369]: all zones loaded

Oct 19 23:59:33 stlnsa named[369]: running

ubuntu@stlnsa:~$ exit <-- logout of the LXC DNS container

logout

Connection to 10.207.39.2 closed.

oracle@u1604:~$ cat /etc/resolv.conf <-- prove that /etc/resolv.conf has not changed

# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)

# DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN

nameserver 127.0.1.1

search orabuntu-lxc.com consultingcommandos.us

oracle@u1604:~$ ssh ubuntu@stlnsa <-- DNS name resolution provided the the DNS LXC container working again!

ubuntu@stlnsa's password:

Welcome to Ubuntu 16.04.1 LTS (GNU/Linux 4.4.0-43-generic x86_64)

* Documentation: https://help.ubuntu.com

* Management: https://landscape.canonical.com

* Support: https://ubuntu.com/advantage

Last login: Wed Oct 19 23:59:26 2016 from 10.207.39.1

ubuntu@stlnsa:~$

The dnsmasq takes credit for all these lookups even though the LXC container DNS bind9 is also doing half the work too! A side benefit is that the identity of the actual DNS nameservers is obfuscated a bit. From the lookup output, one would think that dnsmasq was doing all the lookups by itself!

oracle@u1604:~$ nslookup stlnsa

Server: 127.0.1.1

Address: 127.0.1.1#53

Name: stlnsa.orabuntu-lxc.com

Address: 10.207.39.2

oracle@u1604:~$ nslookup google.com

Server: 127.0.1.1

Address: 127.0.1.1#53

Non-authoritative answer:

Name: google.com

Address: 172.217.6.14

oracle@u1604:~$ nslookup 10.207.39.2

Server: 127.0.1.1

Address: 127.0.1.1#53

2.39.207.10.in-addr.arpa name = stlnsa.orabuntu-lxc.com.

oracle@u1604:~$

LXC DNS Nameserver config File

Some routing is needed because these are static routes. The config file for the LXC container is shown below.

root@u1604:~# cat /var/lib/lxc/stlnsa/config

# Template used to create this container: /usr/share/lxc/templates/lxc-ubuntu

# Parameters passed to the template: -r xenial -a amd64

# For additional config options, please look at lxc.container.conf(5)

# Uncomment the following line to support nesting containers:

#lxc.include = /usr/share/lxc/config/nesting.conf

# (Be aware this has security implications)

# Common configuration

lxc.include = /usr/share/lxc/config/ubuntu.common.conf

# Container specific configuration

lxc.rootfs = /var/lib/lxc/stlnsa/rootfs

lxc.rootfs.backend = dir

lxc.utsname = stlnsa

lxc.arch = amd64

# Network configuration

# lxc.network.type = veth

# lxc.network.link = lxcbr0

# lxc.network.flags = up

# OpenvSwitch Networking

lxc.network.type = veth

lxc.network.flags = up

lxc.network.script.up = /etc/network/if-up.d/openvswitch/stlnsa-pub-ifup-sw1

lxc.network.script.down = /etc/network/if-down.d/openvswitch/stlnsa-pub-ifdown-sw1

lxc.network.veth.pair = stlnsaw

lxc.network.name = eth0

lxc.network.mtu = 1500

lxc.network.hwaddr = 00:16:3e:ce:de:25

# lxc.network.ipv4 = 10.207.39.2/24 <-- Notice that the ip addresses are not set here

lxc.network.type = veth

lxc.network.flags = up

lxc.network.script.up = /etc/network/if-up.d/openvswitch/stlnsa-pub-ifup-sx1

lxc.network.script.down = /etc/network/if-down.d/openvswitch/stlnsa-pub-ifdown-sx1

lxc.network.veth.pair = stlnsax

lxc.network.name = eth1

lxc.network.mtu = 1500

lxc.network.hwaddr = 00:16:3e:ce:de:26

# lxc.network.ipv4 = 10.207.29.2/24 <-- Notice that the ip addresses are not set here

# lxc.start.auto = 1

# lxc.group = onboot

# lxc.start.delay = 20

root@u1604:~#

LXC DNS Nameserver interfaces File

The /etc/network/interfaces file for the LXC DNS nameserver is shown below.

ubuntu@stlnsa:~$ cat /etc/network/interfaces

# This file describes the network interfaces available on your system

# and how to activate them. For more information, see interfaces(5).

# The loopback network interface

auto lo

iface lo inet loopback

auto eth0

iface eth0 inet static

address 10.207.39.2

netmask 255.255.255.0

network 10.207.39.0

broadcast 10.207.39.254

post-up route add default gw 10.207.39.1 metric 1

pre-down route del default gw 10.207.39.1

auto eth1

iface eth1 inet static

address 10.207.29.2

netmask 255.255.255.0

network 10.207.29.0

broadcast 10.207.29.254

post-up route add default gw 10.207.29.1 metric 2

pre-down route del default gw 10.207.29.1

dns-nameservers 10.207.39.2 10.207.29.2 <-- These lines configure /etc/resolv.conf in the container

dns-search orabuntu-lxc.com consultingcommandos.us <--

ubuntu@stlnsa:~$

Note 1

I had an issue with eth1 it was unusable (ping, nslookup. ssh, etc. all not working). It turned out had a misconfig in my files that are used in the LXC config file. Copied he /etc/network/if-up.d/openvswitch/stlnsa-pub-ifup-sw1 script to /etc/network/if-up.d/openvswitch/stlnsa-pub-ifup-sw1 but had forgotten to update the VLAN tag and that of course was the issue as shown below.

oracle@u1604:~$ sudo su -

root@u1604:~# cat /etc/network/if-up.d/openvswitch/stlnsa-pub-ifup-sx1

#!/bin/bash

ovsBr='sx1'

ovs-vsctl add-port ${ovsBr} $5

ovs-vsctl set port $5 tag=11 <-- This had not been updated to "11"; it was still set to sw1 vlan 10.

root@u1604:~#

Once I updated the VLAN tag=11 and restarted everything worked perfectly.