June 6, 2018 · networking linux diy

Personal DHCP & DNS over HTTPS Server

This DHCP + DNS Server build relies on the Raspberry Pi (RPi): the Raspberry Pi is an extremely influential piece of hardware that is small, cheap, low power, and runs a full Linux (GNU/Linux?) system. Originally targeted at getting kids interested in coding and hardware, it has found a home in millions of hardware and software hackers. At my home, it serves multiple roles including a DHCP server, DNS server, HomeKit Bridge (for my air sensors), public SSH server, VPN server, as well as a few other small projects. I find it extremely useful to have a box that stays on 24/7, as opposed to computers that you need to update and restart. Right now the uptime is 15 days, but that's definitely cut short because I have frequent power outages...

The two critical network services required by almost every device is DHCP and DNS. Local networks have something called a subnet, or a range of local IP addresses that only correspond to devices within your home network. DHCP provides each device with a unique local IP address. DHCP also tells your device how to access the wide area network, or what is colloquially known as the internet, by providing devices with the IP address of your router. Next, DNS servers provide devices with name resolution, i.e. it takes in strings like "google.com" and outputs an IP address like "172.217.1.14". Services like DNS and DHCP were devised before security and encryption had entered the collective consciousness of the tech community, so they were insecure by design. Unlike DNS, DHCP activity only traverses over your local network cables, so remaining insecure is typically fine. However, DNS requests go unencrypted over the internet, and allow for ISPs to track you and expose you to potential man-in-the-middle attacks. DNS over HTTPS is a solution that works by encrypting all DNS data. For an amazing writeup about DNS over HTTPS, check out Mozilla's cartoon intro to DNS over HTTPS.

I used two pieces of software: dnsmasq and Unbound. Unbound provides DNS over HTTPS, while dnsmasq provides DHCP and standard DNS. The advantage to using dnsmasq for the first layer of DNS is that it provides local name resolution, i.e. I can type ssh yoonsik@macair, and have it connect.

dns_diagram-1

First, make sure that your RPi has a static IP address. You can do this by editing the following file: sudo nano /etc/network/interfaces

# interfaces(5) file used by ifup(8) and ifdown(8)

# Please note that this file is written to be used with dhcpcd
# For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'

# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
    address 172.16.0.100
    netmask 255.255.255.0
    gateway 172.16.0.1
    dns-search lan.

Where it says iface eth0 inet dhcp, replace it with the above. Then disable the DHCP daemon on your Raspberry Pi, by typing the following commands: sudo systemctl disable dhcpcd and sudo systemctl enable networking. Reboot. You will now have to SSH using the static IP address.

Next, install dnsmasq running sudo apt-get install dnsmasq. After that, edit the dnsmasq configuration file by typing sudo nano /etc/dnsmasq.conf.

These are the lines that need to be uncommented/edited:

# Never forward plain names (without a dot or domain part)
domain-needed

# Never forward addresses in the non-routed address spaces.
bogus-priv

# If you don't want dnsmasq to read /etc/resolv.conf or any other
# file, getting its servers from this file instead (see below), then
# uncomment this.
no-resolv

# Add local-only domains here, queries in these domains are answered
# from /etc/hosts or DHCP only.
local=/lan/
server=1.1.1.1

# Set the domain for dnsmasq. this is optional, but if it is set, it
# does the following things.
# 1) Allows DHCP hosts to have fully qualified domain names, as long
#     as the domain part matches this setting.
# 2) Sets the "domain" DHCP option thereby potentially setting the
#    domain of all systems configured by DHCP
# 3) Provides the domain part for "expand-hosts"
domain=lan.

dhcp-authoritative

# Uncomment this to enable the integrated DHCP server,
dhcp-range=172.16.0.101,172.16.0.199,2h

# Override the default route supplied by dnsmasq
# Do the same thing, but using the option name
dhcp-option=option:router,172.16.0.1

For the very last two configurations, make sure to check what your current DHCP range and router address is. For example, most popular range is 192.168.0.2,192.16.0.199, and having a router with IP address 192.168.0.1.

Restart dnsmasq with sudo service dnsmasq restart.

Next run the following commands to remove the local DNS services running in the background.

$ sudo apt remove openresolv
$ sudo systemctl disable systemd-resolved.service
$ sudo service systemd-resolved stop

Then edit the DNS server list file by typing sudo nano /etc/resolv.conf. Make sure the file looks exactly like this:

search lan
nameserver 127.0.1.1

Finally, we install Unbound: sudo apt install unbound

Then edit the Unbound configuration files: sudo nano /etc/unbound/unbound.conf
So it looks like this:

include: "/etc/unbound/unbound.conf.d/*.conf"
server:
  port: 5353

Then, edit the forwarding file:

sudo nano /etc/unbound/unbound.conf.d/forward-zone.conf

forward-zone:
  name: "."
  forward-addr: 1.1.1.1@853
  forward-addr: 1.0.0.1@853
  forward-addr: 2606:4700:4700::1111@853
  forward-addr: 2606:4700:4700::1001@853
  forward-ssl-upstream: yes   

Restart Unbound with sudo service unbound restart.

Lastly, edit your dnsmasq configuration file by typing sudo nano /etc/dnsmasq.conf, and change the server line to

server=127.0.0.1#5353

Restart dnsmasq again with sudo service dnsmasq restart.

Finally, you have Unbound as your actual secure DNS Server, with dnsmasq providing local name resolution and DHCP for all your devices.

Additional Notes: You may want to explore configuring qname-minimisation.conf and root-auto-trust-anchor-file.conf