Privacy: Using DNS-over-TLS with the Quad9 DNS Service
Update 1 April 2018: Yes, this also works for Cloudflare’s #1dot1dot1dot1
Recently the Quad9 DNS service was launched, a collaboration between IBM, Packet Clearing House (PCH) and the Global Cyber Alliance (GCA). According to the GCA, the Quad9 DNS server clusters are load-balanced with dnsdist and use a mix of Unbound and PowerDNS servers to deliver responses, giving the whole service a special Dutch flavour 🙌🇳🇱🙌.
Quad9 differentiates from similar services by focussing on ease-of-use, scalability, security and privacy. One interesting and seemingly undocumented feature is the fact that you can communicate with the service using DNS-over-TLS. This encrypts the communication between your client and the DNS server, safeguarding your privacy.
We can get this functionality working using GetDNS, a modern asynchronous DNS API that NLnet Labs contributes to. As GetDNS is a library, we need a stub resolver that can talk to it. Stubby is a local stub resolver daemon that links with GetDNS to make this work on your system. Stubby is available for Windows, macOS and Linux. In this demo I’ll be using a Mac, so the easiest way to get started is by installing Homebrew, if you don’t already have it.
/usr/bin/ruby -e “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
Next, we can install Stubby.
brew install stubby
Stubby relies on a configuration file in YAML (Yet Another Markup Language), open
/usr/local/etc/stubby/ in order to edit it.
By default you’ll see that
GETDNS_TRANSPORT_TLS is the only transport protocol that is enabled. For this demo, we want to keep it this way to make sure that we only communicate over TLS and have no means to fall back to TCP or UDP. We also want the usage profile to be ‘Strict’. This means that authentication information for the upstreams must be specified in the configuration file. Look for the line
tls_authentication and ensure it is set to
A little bit further down you will find a list with upstream recursive name servers that Stubby will send queries to. Several test servers are being operated by organisations such as SURFnet, Go6Lab and NIC Chile. All of them have an IP address, a hostname for TLS authentication and a Base 64 encoded form of SPKI pin(s) for TLS authentication (RFC7858).
We can query for the current SPKI pin for Quad9, but as DNS-over-TLS is an undocumented feature and we don’t know what their policy is, keep in mind that the key may be rolled by at any time. You can always get the latest SPKI pin with this command.
echo | openssl s_client -connect '220.127.116.11:853' 2>/dev/null | openssl x509 -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
It should return with a value like this.
Now we have all the required elements to edit the config file.
- address_data: 18.104.22.168
- digest: "sha256"
Make sure you are careful with the spacing, YAML can be quite finicky about it. Next I comment out all of the other servers, make sure that Quad9 is the only one left. Save the file and we only have a couple of steps to go.
For Stubby to send outgoing DNS queries over TLS the resolvers configured on your machine must be changed to send all the local queries to the loopback interface on which Stubby is listening. To do this on my Mac, I run this command.
You can check in System Preferences that for the current network interface the DNS servers have changed to
::1. Looks like we’re ready to go, so the next step is to fire up Stubby pointing at the configuration file we just made and ensure that logging is enabled with
-l so we can keep track of what its doing.
sudo stubby -C /usr/local/etc/stubby/stubby.yml -l
To learn more about DNS Privacy, please visit https://dnsprivacy.org/ , a collaborative open project to promote, implement and deploy DNS Privacy.
Update 17 January 2018: In case you’re a Mac user, I’ve been running the alpha version of StubbyManager for MacOS with no problems for several weeks now.