DNS over TLS with DNSMASQ and Stubby on Asuswrt-Merlin

What is DNS?

The Domain Name System (DNS) is what allows you to access the websites you want.  DNS is like a phone-book where you can find all the websites available online. In this phone-book, every single website is assigned a specific “phone number” or IP address. When you type the name of a website, your ISP goes inside the “phone-book” or DNS server, extracts the IP address of the website you are looking for and uses it to connect you with it.

However, DNS is one of the most significant data privacy leaks of data about an individual’s activity on the Internet. DNS queries are sent in clear text using UDP or TCP protocols.  An eavesdropper can observe all the DNS lookups you perform.  Some Internet Service Providers (ISPs) log DNS queries and may share this information with third-parties or sell the information to advertisers.

Securing DNS Queries using Stubby DNS over TLS

DNS over TLS is a security protocol for encrypting and wrapping DNS queries and answers using the Transport Layer Security (TLS) protocol.  The goal of the method is to increase user privacy and security by preventing eavesdropping and manipulation of DNS data via man-in-the-middle attacks.

Stubby is an application that acts as a local DNS Privacy stub resolver using DNS-over-TLS. Stubby encrypts DNS queries sent from a client machine to a DNS Privacy resolver increasing end user privacy.

Stubby is developed by the getdns project and has its own GitHub repositorydnsprivacy.org hosts the online documentation for Stubby.

Adventures with Stubby on Asuswrt-Merlin

The entware maintainers released Stubby 0.2.3 on the entware repository in September 2018. However, there were no resources available on how to configure Stubby to work on Asuswrt-Merlin.

I started my journey by searching the internet.  I found a Stubby tutorial for OpenWRT firmware that appeared to be the most relevant to Asuswrt-Merlin firmware.

Required Entware Packages

I first started by installing the entware packages stubby and ca-certificates.

opkg install stubby
opkg install ca-certificates

DNSMASQ

According to the guide, the following entries are required in dnsmasq:

no-resolv
server=127.0.0.1#5453
server=0::1#5453

The no-resolv parameter instructs dnsmasq not to read /tmp/resolv.conf. And instead, get the upstream servers from the command line or the dnsmasq.conf configuration file. I did not have to add the no-resolv parameter since it was already in /tmp/etc/dnsmasq.conf. The last two server entries instruct dnsmasq to forward DNS requests to Stubby on port 5453. To customize dnsmasq on Asuswrt-Merlin, one must have the jffs partition enabled. Then, create the file /jffs/configs/dnsmasq.conf.add and add the two server parameters to the file.

WAN DNS

I then tried changing the WAN DNS1 server to 127.0.0.1. But the edits in the Web GUI prevents the use of the router loopback address 127.0.01. I worked around the issue by using setting WAN DNS1 to 127.0.0.1 and WAN DNS2 to null by using the nvram set and commit commands:

#Set DNS1 to 127.0.0.1
DNS1=127.0.0.1
# Set DNS1 based on user option
nvram set wan0_dns="$DNS1"
nvram set wan_dns="$DNS1"
nvram set wan_dns1_x="$DNS1"
nvram set wan0_xdns="$DNS1"
nvram set wan0_dns1_x="$DNS1"
# Set DNS2 to null
nvram set wan_dns2_x=""
nvram set wan0_dns2_x=""
# Commit nvram values
nvram commit

After posting updates on my progress in the Stubby SNBForums thread, another forum member reported success with using the Router’s IP address for DNS1. This is a much better solution as it solves the issue of not being able to apply changes on the WAN page when setting WAN DNS1 to 127.0.0.1.

Starting Stubby

A restart of dnsmasq is required for the changes to /jffs/configs/dnsmasq.conf.add to take effect. This can be done using the command service restart_dnsmasq in an SSH session.

To start stubby, I adopted the command used by John9527, the developer of the the Asuswrt-Merlin-Fork, to start Stubby:

stubby -g -v 5 -C /opt/etc/stubby/stubby.yml 2>/opt/var/log/stubby.log

However, I wanted Stubby to start at system boot. Some entware packages automatically install a start-up script in the directory /opt/etc/init.d. I copied one of the existing scripts into the file called S61stubby. I used S61 as the first three letters of the file name to match the number used by the entware package unbound, another DNS resolver. Entware will start the packages according to ascending order.  For example, S01fake-hwclock will start before the S80pixelserv-tls start-up script.  Following are the contents of the /opt/etc/init.d/S61stubby file:

#!/bin/sh
logger -t S61stubby "Starting Stubby DNS over TLS $0"
# set environment PATH to system binaries
export PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH
ENABLED=yes
PROCS=stubby
ARGS="-g -v 5 -C /opt/etc/stubby/stubby.yml 2>/opt/var/log/stubby.log"
PREARGS="nohup"
DESC=$PROCS
PATH=/opt/sbin:/opt/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
. /opt/etc/init.d/rc.func

One issue I had that others also reported is finding that the Stubby process was not running after exiting the SSH session from which it was started from. The PREARGS=”nohup” parameter resolved the issue. You can verify that Stubby is running using the following commands:

ps | grep stubby | grep –v grep
/opt/etc/init.d/S61stubby status

Cloudflare Test Page and DNSSEC

During my initial testing, I used the default stubby.yml configuration file created during the installation of the package and configured it to use Cloudflare 1.1.1.1.  I preferred to use Cloudflare during my initial testing as Cloudflare has a test page https://1.1.1.1/help that one can use to validate that DNS over TLS is working. However, the site will not work if DNSSEC is enabled in the firmware. I also turned it off to avoid conflicts with the Zero Configuration DNSSEC feature built into getdns.

Stubby Integration with OpenVPN Clients

In my testing, I found Stubby would not work when I bounced one of the OpenVPN clients. I discovered the firmware will populate /tmp/resolv.dnsmasq with both the WAN DNS1 and the OpenVPN DNS entries 10.9.0.1 and 10.8.0.1 during an OpenVPN up event.  The addition of the VPN DNS in /tmp/resolv.dnsmasq prevented Stubby from working. I resolved the issue by creating the file /jffs/configs/resolv.dnsmasq with the value server=x.x.x.x, where x’s are my LAN IP address, and adding an entry in /jffs/scripts/openvpn-event to copy /jffs/configs/resolv.dnsmasq to /tmp/resolv.dnsmasq.

I tested each Accept DNS Configuration setting when using one and multiple OpenVPN Clients and had no issues. To configure an OpenVPN Client to use Stubby DNS, set Accept DNS Configuration = Disabled on the VPN->VPN Client page. Select the Apply button to save the setting.

Entware Package ca-certificates

In the final version, I eliminated the requirement to use the ca-certificates entware package by changing the tls_ca_file parameter in the stubby.yml file to use the ca-certificates.crt file installed by the firmware in the /rom/etc/ssl/certs/ directory rather than the ca-certificate.crt file located in/opt/etc/ssl/certs/.

Summary

My one complaint with Stubby is that logging of system messages is non-existent. I hope this will improve in future releases.  DNS lookup queries will still appear in the dnsmasq.log file though.  And other commands can be used to validate that Stubby is working.  Since Stubby is in the early stages of development, it may not be suitable for non-technical users. To assist users of all levels implement Stubby, I wrote a Stubby installer script to make the process easier. The script defaults to Cloudflare (1.1.1.1) DNS-over-TLS on port 853. You can change to other supported public or test resolvers by updating the Stubby configuration file located in /opt/etc/stubby/stubby.yml. For more information on Stubby, including how to install and validate, visit the Stubby-Installer-Asuswrt-Merlin GitHub Repository.