Why and how to encrypt DNS queries on Linux
Table of Contents
Intro
If you know how it works feel free to skip to the hands-on part.
DNS (Domain Name System) is a big part of the Internet. Its role is primarily to convert domain names to IP addresses.
Historically, DNS is unencrypted; which means anyone can see all of the DNS queries issued by your computer, such as your Internet Service Provider (ISP) or someone on the same network as you. As your computer issues a DNS query for every website you visit, it’s very easy to draw a profile of who you are based on your browsing history.
Furthermore, as there is no authenticity check at the DNS level (which
encryption would provide), requests can be tampered with. For example, your ISP
may decide to send you the wrong IP address for badgovernment.com
, which would
prevent you from accessing it. It’s common practice in many countries:
governments ask ISPs to block some websites they consider “illegal”. This is in
direct contradiction with the principle of net
neutrality.
Luckily, there are solutions to these problems!
DoH, DoT, DoWhat ?
Several protocols have been developed in order to bring encryption to DNS. I will talk about two of them. They invented nothing as they’re built on top of existing and secure encryption protocols.
DNS-over-HTTPS
The name is quite clear: it’s DNS inside HTTPS. For each DNS query, your computer will send an HTTPS query encapsulating the DNS request. The server will then respond via HTTPS as well.
HTTPS is widely used nowadays and uses TLS, which is a well-known encryption protocol. The main advantage is that we have almost nothing to change, because everybody already uses HTTPS.
The other advantage of this approach is that it goes through the network port of HTTPS, which is 443 — of course because it’s HTTPS! It is an important point because in some countries, most ports are blocked, except 80 (HTTP) and 443 (HTTPS) for Web traffic.
DNS-over-TLS
No HTTPS this time but encryption is handled by TLS (which is included in HTTPS).
Therefore we use the same encryption protocol as in DNS-over-HTTPS, without the HTTP layer. This results in smaller requests than with HTTPS.
The drawback is the dedicated port: DNS-over-TLS uses port 853, that governments willing to control people’s DNS queries may ask ISPs to block.
However, regarding query security, the two protocols are equivalent.
Configure DNS-over-TLS on Linux
We will use DNS-over-TLS, because the reference implementation in Linux does not yet support DNS-over-HTTPS, and I have no port restrictions in my country. In order to speed up DNS queries, we will also install a DNS cache. Its role will be to remember DNS responses, so that we’ll get a faster response for subsequent identical queries.
Overview
Stubby is a DNS resolver that implements DNS-over-TLS. It will act as a proxy between your computer’s DNS queries and the remote server’s response.
We’ll also configure dnsmasq as a DNS cache. It will temporarily remember DNS responses so that it can answer quickly the next time instead of asking a remote server every time.
We will have to configure our computer to query dnsmasq, then dnsmasq to query Stubby, and finally Stubby to query a remote server. With this setup dnsmasq will be able to cache DNS responses from Stubby.
Installing Stubby
Install the stubby
package with your distribution’s package manager.
Example for Debian/Ubuntu:
# apt install stubby
Let’s configure Stubby. Its configuration file is located in
/etc/stubby/stubby.yml
. The default file is quite long (500 lines) but it’s
primarily comments explaining all the possible configuration values.
First, let’s change Stubby’s listening port. We’ll make it listen on another port than the default one (53) because it will be dnsmasq’s role to answer queries, so dnsmasq will be the one listening on port 53.
By default, Stubby listens locally on port 53:
################################ LISTEN ADDRESS ################################
# Set the listen addresses for the stubby DAEMON. This specifies localhost IPv4
# and IPv6. It will listen on port 53 by default. Use <IP_address>@<port> to
# specify a different port
listen_addresses:
- 127.0.0.1
- 0::1
Let’s tell it to listen on port 53420 (more or less a random choice):
listen_addresses:
- 127.0.0.1@53420
- 0::1@53420
The other interesting part is the DNS servers configuration, the “upstreams”. They are the remote servers that Stubby will query via DNS-over-TLS.
Some servers are enabled by default, some others are commented out. Feel free to keep the default configuration or to do some research about existing public DNS-over-TLS servers.
I personally use Cloudflare’s servers:
upstream_recursive_servers:
- address_data: 1.1.1.1
tls_auth_name: "cloudflare-dns.com"
- address_data: 1.0.0.1
tls_auth_name: "cloudflare-dns.com"
- address_data: 2606:4700:4700::1111
tls_auth_name: "cloudflare-dns.com"
- address_data: 2606:4700:4700::1001
tls_auth_name: "cloudflare-dns.com"
The goal is to choose a fast server respecting your privacy; that is which doesn’t log your queries! Indeed, if your ISP does not see your DNS queries anymore thanks to DNS-over-TLS the DNS server still sees them — fortunately, otherwise it couldn’t answer them.
Let’s start Stubby and make it auto-start at boot:
# systemctl start stubby
# systemctl enable stubby
Note that these two commands may be combined to:
# systemctl enable --now stubby
Installing dnsmasq
dnsmasq is a fully-featured tool (DNS resolver, DHCP server…) but we’ll only use it here as a DNS cache. It’s a common practice.
Install the dnsmasq
package with your distribution’s package manager.
Example for Debian/Ubuntu:
# apt install dnsmasq
We have to tell dnsmasq to redirect all queries to Stubby. We configured Stubby to listen on port 53420. Let’s tell dnsmasq to send queries to that port!
Its configuration file is located in /etc/dnsmasq.conf
.
# Do not read /etc/resolv.conf, use servers below instead
no-resolv
# Use local Stubby server on port 53420
server=127.0.0.1#53420
server=::1#53420
Then, we have to make dnsmasq listen locally on port 53 (which is the default port):
listen-address=::1,127.0.0.1
We will also enable DNSSEC proxying. I won’t go into details here but it’s a way to authenticate DNS responses. I recommend you add this option:
proxy-dnssec
Finally, I recommend you increase dnsmasq’s cache size. By default it can cache up to 150 responses. This is quite low given the number of websites one can visit in a few minutes! I personally greatly increased this value:
cache-size=2000
That’s it! Let’s start dnsmasq and auto-start it at boot:
# systemctl enable --now dnsmasq
Tell the system to use dnsmasq
When your computer issues DNS queries it uses the servers provided by the network it is in — often, the ones from your ISP — unless you changed that behaviour.
We want to use dnsmasq as our DNS server because it will redirect all requests to Stubby, which is responsible for querying the “upstream” servers in an encrypted manner.
If your system uses NetworkManager — it probably does — we have to tell it not to use the DNS servers provided by the network but our own machine instead.
Let’s create a file /etc/NetworkManager/conf.d/dns.conf
with the following
content:
[main]
dns=none
Lastly, let’s change the system’s DNS configuration file to put our own machine as a DNS server.
Open /etc/resolv.conf
and make sure the only nameserver
is 127.0.0.1
:
nameserver 127.0.0.1
All of your computer’s software read that file to know which DNS server to query. With this configuration they will query the local server running on port 53, which is dnsmasq!
Note about browsers shipping with built-in DNS-over-HTTPS
Some browsers, such as Mozilla Firefox, ship with built-in DNS-over-HTTPS — although it may not be enabled by default. Thanks to our configuration we can disable this setting: Firefox will always use the system’s DNS server, which is dnsmasq, so we’ll still have encrypted queries. Moreover, they’ll be cached, so even faster!
Conclusion
I hope this post helped you understand why DNS encryption is important and how to make it work on Linux.
Please don’t hesitate to reach me by e-mail if you have any comments!