negative zero

Encrypted DNS with Stubby

2023 January 3

[dns] [privacy] [tech] [tutorial]


What is DNS?

The Domain Name System (DNS) is the system for translating domain names (such as example.com) to IP addresses (such as 12.34.56.78). It's also used for some other stuff, but that's the most common thing. Generally, it tells you how to interact with domains.


Why encrypt DNS?

Privacy

Like many internet protocols, DNS was not designed with privacy or security in mind. By default, your internet service provider can read your DNS queries and modify them as desired. (In fact, in most cases, your ISP provides the DNS resolution service by default, giving it full control.) By using a different DNS provider and encrypting your DNS queries, you make it harder (though not impossible) for your ISP to determine which domains you connect to.

Censorship resistance

If your ISP wants to prevent you from connecting to certain domains, it may do this by blocking DNS queries for that domain. If your ISP can't tell which domains you're looking up, it can't selectively block those requests. As with the privacy case, blocking DNS queries is not the only way to block domains, but using a different DNS provider and encrypting your queries may circumvent your ISP's restrictions.


Given that domain names are sent unencrypted in HTTPS anyway, is there any point in doing this?

I can't answer that about your situation. If your ISP is relying only on DNS to track or censor your use of the internet, then yes. If you want a more thorough protection, then it would be better to use Tor, a VPN, etc.


What if I'm using a VPN/Tor/etc.?

These tools generally proxy your DNS queries, meaning the VPN server or exit node will do its own DNS lookup instead of you doing it. This guide doesn't apply to these situations.


Which approach to DNS encryption will this take?

This guide is for DNS-over-TLS (DoT). Other options include DNS-over-HTTPS and DNSCrypt. Here's a video with more on this topic.


What software do I need?

This guide assumes you're running desktop Linux and uses Stubby as the DNS resolver. Stubby also runs on macOS and Windows, and the process is probably somewhat similar.

Another option for Linux is using systemd-resolved.

Android is not covered at all by this guide, but Android 11+ supports DNS-over-TLS natively, and a guide can be found here.


Guide

Install Stubby

First, install stubby. This is likely available through your package manager.


Configure Stubby

Next, modify the stubby config file, /etc/stubby/stubby.yml.

Set the following rules:

dns_transport_list:
  - GETDNS_TRANSPORT_TLS

tls_authentication: GETDNS_AUTHENTICATION_REQUIRED

This requires DNS over TLS.

listen_addresses:
  - 127.0.0.1
  - 0::1

Stubby will listen on localhost.

You may set your DNSSEC preferences as you choose. DNSSEC does not have to do with encryption; it has to do with authenticating domains. If you require DNSSEC authentication, you can be more confident that responses to your DNS queries are legitimate, but you also may run into performance issues including inability to resolve some domains at all.

Choose the upstream DNS provider(s) you want. There are good reasons to choose different options. You may want, for example, to choose OpenNIC servers which support DoT. You may want to use DNS servers which filter malicious domains. You may want DNS servers which have pinned TLS certificates to protect against PITM attacks by your ISP. PrivacyGuides has a list of recommended providers which might be useful to you.

I will demonstrate using Quad9:

upstream_recursive_servers:
  - address_data: 9.9.9.9
    tls_auth_name: "dns.quad9.net"
  - address_data: 2620:fe::fe
    tls_auth_name: "dns.quad9.net"

I have all the other providers commented out.

Save this file.

If you're using SystemD, you can run Stubby and have it run at boot:

sudo systemctl enable --now stubby


Set Stubby as your DNS resolver

Now, you need to set Stubby (running on localhost:53) as your DNS resolver.

If you're using NetworkManager (if you don't know, you probably are), add a file at /etc/NetworkManager/conf.d/00-dns-servers.conf:

[global-dns-domain-*]
servers=::1,127.0.0.1

Restart NetworkManager:

sudo systemctl restart NetworkManager

cat your /etc/resolv.conf to check that it applied correctly. It should look something like this:

# Generated by NetworkManager
nameserver ::1
nameserver 127.0.0.1

If you're not using NetworkManager (or if that failed), you may need to modify some other config file. See this question for example. One way to set this is to manually edit /etc/resolv.conf (to have only the above nameserver commands) and then make it immutable so it doesn't get overwritten:

sudo chattr +i /etc/resolv.conf

A quick test to see if Stubby is your DNS provider: Do something that requires a DNS query, e.g., curl https://lost.negativezero.link/. Then stop Stubby (e.g., with sudo systemctl stop stubby) and try again. If Stubby is your only DNS resolver, it should work when Stubby is running and not when Stubby is not. Or you could dig and see which SERVER is used. (It should be ::1#53 or 127.0.0.1:53.)