Configure DoT on systemd-resolved
I run own DNS-over-TLS (DoT) and DNS-over-HTTPS (DoH) servers at dns.shivering-isles.com
for quite a while now. Finally I made it to configure my Fedora system to use these DNS servers for all DNS queries, not just the ones from the browser.
The knowledge gained by that, might be useful to others as well, therefore this article provides a little tutorial about configuring such a DoT endpoint in systemd-resolved
on Fedora.
Configure systemd-resolved
First you can use this little generator script to make it easier to keep the DNS configuration up-to-date:
#!/bin/sh
RESOLVER="${1:-dns.shivering-isles.com}"
DNS_SERVERS=""
for dns in $(dig ${RESOLVER} +short && dig ${RESOLVER} +short AAAA); do
DNS_SERVERS+="$dns#${RESOLVER} "
done
cat <<EOF
[Resolve]
DNS=$DNS_SERVERS
FallbackDNS=$DNS_SERVERS
Domains=~.
DNSOverTLS=yes
DNSSEC=yes
EOF
This script queries all IP addresses for dns.shivering-isles.com
and appends #dns.shivering-isles.com
at the end to inform systemd-resolved
about the SNI name to use. As DoT also relies on x509 certificates, it’ll take the name from the remote certificate and validate it with the name provides after the #
. If this is not correctly specified, DoT will simply fail due to untrusted connections.1
The output of the script is a configuration for systemd-resolved
, that contains the DNS servers using DNS=
and FallbackDNS=
, sets them as default domain handlers using Domains=~.
, enables DoT using DNSOverTLS=yes
and enforces DNSSEC2 using DNSSEC=yes
. This makes sure that the global default is secure and actually uses dns.shivering-isles.com
.
The next step is to use the configuration generator script to configure systemd-resolved
:
$ sudo mkdir -p /etc/systemd/resolved.conf.d/
$ generate-dns-config.sh | sudo tee /etc/systemd/resolved.conf.d/shivering-isles-dns.conf
$ systemctl restart systemd-resolved
The directory /etc/systemd/resolved.conf.d/
can be used for drop-in configurations, allowing easier maintenance of the default configurations by the distribution. With sudo tee …
you can drop the configuration into the file called shivering-isles-dns.conf
and get the same output to your shell for validation. Finally you restart of systemd-resolved
. If the DNS configuration ever turns out to be broken, removing the file and restarting the daemon is enough to go back to default settings.
Configure NetworkManager
To take actual advantage of this global configuration, you have to disable the per-interface configuration that NetworkManager provides. You can add another drop-in configuration, but this time for NetworkManager:
$ sudo mkdir -p /etc/NetworkManager/conf.d/
$ sudo tee /etc/NetworkManager/conf.d/01-dns.conf <<EOF
[main]
dns=none
systemd-resolved=false
EOF
dns=none
tells NetworkManager to not touch /etc/resolv.conf
as you still want to use the systemd-resolved
service there. systemd-resovled=false
tells NetworkManager to stop talking to systemd-resolved
, and therefore no longer advertising any DNS settings from interface configurations to it.
The downside of this configuration is, that the DNS settings in NetworkManager are now useless. But in return all interfaces now use the global configuration in future, which is pointing at dns.shivering-isles.com
.
To verify the result you can use the command resolvectl
.
$ resolvectl
Global
Protocols: LLMNR=resolve -mDNS +DNSOverTLS DNSSEC=yes/supported
resolv.conf mode: stub
Current DNS Server: 159.69.205.48#dns.shivering-isles.com
DNS Servers: 159.69.205.48#dns.shivering-isles.com 159.69.93.12#dns.shivering-isles.com 2a01:4f8:c2c:4e81:cafe::2#dns.shivering-isles.com
2a01:4f8:c2c:5348::1#dns.shivering-isles.com
DNS Domain: ~.
Link 2 (enp0s25)
Current Scopes: DNS LLMNR/IPv4 LLMNR/IPv6
Protocols: +DefaultRoute +LLMNR -mDNS +DNSOverTLS DNSSEC=yes/supported
Current DNS Server: 1.1.1.1
DNS Servers: 1.1.1.1 9.9.9.9
DNS Domain: ~.
Link 3 (wwp0s20u4)
Current Scopes: none
Protocols: -DefaultRoute +LLMNR -mDNS +DNSOverTLS DNSSEC=yes/supported
Link 4 (wlp3s0)
Current Scopes: LLMNR/IPv4 LLMNR/IPv6
Protocols: -DefaultRoute +LLMNR -mDNS +DNSOverTLS DNSSEC=yes/supported
DNS Domain: ~.
Link 6 (virbr0)
Current Scopes: none
Protocols: -DefaultRoute +LLMNR -mDNS +DNSOverTLS DNSSEC=yes/supported
Link 7 (virbr0-nic)
Current Scopes: none
Protocols: -DefaultRoute +LLMNR -mDNS +DNSOverTLS DNSSEC=yes/supported
In this output you might notice that enp0s25
still has an own DNS server configured. To remove it, you can run resolvectl dns enp0s25 ""
.
Afterwards it should look like this:
$ resolvectl
Global
Protocols: LLMNR=resolve -mDNS +DNSOverTLS DNSSEC=yes/supported
resolv.conf mode: stub
Current DNS Server: 159.69.205.48#dns.shivering-isles.com
DNS Servers: 159.69.205.48#dns.shivering-isles.com 159.69.93.12#dns.shivering-isles.com 2a01:4f8:c2c:4e81:cafe::2#dns.shivering-isles.com
2a01:4f8:c2c:5348::1#dns.shivering-isles.com
DNS Domain: ~.
Link 2 (enp0s25)
Current Scopes: LLMNR/IPv4 LLMNR/IPv6
Protocols: -DefaultRoute +LLMNR -mDNS +DNSOverTLS DNSSEC=yes/supported
DNS Domain: ~.
Link 3 (wwp0s20u4)
Current Scopes: none
Protocols: -DefaultRoute +LLMNR -mDNS +DNSOverTLS DNSSEC=yes/supported
Link 4 (wlp3s0)
Current Scopes: LLMNR/IPv4 LLMNR/IPv6
Protocols: -DefaultRoute +LLMNR -mDNS +DNSOverTLS DNSSEC=yes/supported
DNS Domain: ~.
Link 6 (virbr0)
Current Scopes: none
Protocols: -DefaultRoute +LLMNR -mDNS +DNSOverTLS DNSSEC=yes/supported
Link 7 (virbr0-nic)
Current Scopes: none
Protocols: -DefaultRoute +LLMNR -mDNS +DNSOverTLS DNSSEC=yes/supported
And that’s it. You can verify the result using Wireshark if you want. You should only see encrypted network traffic when you run:
$ resolvectl query shivering-isles.com
shivering-isles.com: 2a03:4000:1e:194::1 -- link: enp0s25
78.47.234.185 -- link: enp0s25
185.207.105.117 -- link: enp0s25
-- Information acquired via protocol DNS in 148.3ms.
-- Data is authenticated: yes
Consequences
All in all, this works very well so far, no more unencrypted DNS network traffic. This prevents network-based attacks on DNS as well as reducing the information exposure.3
This is an important step to more secure network communications. DNS is the backbone for basically all applications on the internet, so even when you don’t even notice the difference, in best case, it’ll help to prepare a better future internet.
Note: It is worth mentioning that this setup doesn’t work flawless with container technologies such as docker
and podman
, since containers will be unable to contact systemd-resolved
while using network isolation. This is however solvable by providing the --dns
-parameter or setting a specific, regular DNS server in the configuration. Of course, this means that the containers don’t benefit from secured DNS.
-
If not SNI name is specified, DoT will fallback to the information it has, the IP address, to verify the certificate validity. ↩
-
There are some known issues with
systemd-resolved
and DNSSEC at the time of writing this article. ↩ -
Note that an attacker or network provider can still farm SNI headers to keep track of the websites you visit. ↩