4 minute read

For many years I’ve been using the DNS over TLS (DoT) using quad9 DNS service, preventing anybody from wiretapping and/or hijacking what website I’m visiting on my browser. Since I moved my local services to .internal I was not able to resolve their DNS entries. This is how I configured my laptop to enjoy DNS over TLS and allow .internal services to be resolved too.

What is DNS over TLS?

DNS over TLS (DoT) is a security protocol that encrypts communication between your device and a DNS server over port 853. It protects your privacy and ensures the integrity of the data. Imagine it like sending your DNS requests and responses in a sealed envelope instead of a postcard, making it much harder for anyone to intercept or tamper with them. DoT is especially important in situations where you’re using public Wi-Fi.

Overview

We will enable ability to encrypt DNS queries system-wide and send them to quad9 servers. This means that we will not use the DNS servers given to us by DHCP connections, I always use the quad9 ones. This is true except for the resolution of .internal domain names in my home network.

Configure DoT

Step 1. Edit your /etc/systemd/resolved.conf.d/50-DNSOverTLS.conf by adding the following:

[Resolve]
# AdGuard
# DNS=94.140.14.14#dns.adguard-dns.com 94.140.15.15#dns.adguard-dns.com 2a10:50c0::ad1:ff#dns.adguard-dns.com 2a10:50c0::ad2:ff#dns.adguard-dns.com

# quad9
DNS=9.9.9.9#dns.quad9.net 149.112.112.112#dns.quad9.net 2620:fe::fe#dns.quad9.net 2620:fe::9#dns.quad9.net

# Always use DNS over TLS
DNSOverTLS=yes
Domains=~.

Adding Domains: ~., I force that all DNS queries are routed to quad9 resolvers over DoT. It means that the per link DNS resolvers will not be taken into consideration.

Step 2. Save the configuration and restart the systemd-resolved

sudo systemctl restart systemd-resolved

Step 3. Check the results

$ resolvectl status
Global
         Protocols: -LLMNR -mDNS +DNSOverTLS DNSSEC=no/unsupported
  resolv.conf mode: foreign
Current DNS Server: 9.9.9.9#dns.quad9.net
       DNS Servers: 9.9.9.9#dns.quad9.net 149.112.112.112#dns.quad9.net 2620:fe::fe#dns.quad9.net 2620:fe::9#dns.quad9.net
        DNS Domain: ~.

Link 2 (enxd0c0bf2e92c0)
    Current Scopes: DNS
         Protocols: +DefaultRoute -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
Current DNS Server: 192.168.1.3
       DNS Servers: 192.168.1.3 192.168.1.10

Link 3 (wlp0s20f3)
    Current Scopes: none
         Protocols: -DefaultRoute -LLMNR -mDNS +DNSOverTLS DNSSEC=no/unsupported

The quad9 servers are set at Global level which route all the domains ~. and DNSOverTLS is enabled.

Check one domain:

$ resolvectl query example.com                                    
example.com: 104.20.23.154                     -- link: enxd0c0bf2e92c0
             172.66.147.243                    -- link: enxd0c0bf2e92c0
             2606:4700:10::ac42:93f3           -- link: enxd0c0bf2e92c0
             2606:4700:10::6814:179a           -- link: enxd0c0bf2e92c0

-- Information acquired via protocol DNS in 31.8ms.
-- Data is authenticated: no; Data was acquired via local or encrypted transport: yes
-- Data from: network

As you can see Data was acquired via local or encrypted transport: yes means that this DNS query was encrypted.

Another way to see which protocol you’re using is going to on.quad9.net or by CLI:

$ dig +short txt proto.on.quad9.net.                              
"dot"

What about .internal domains

After moving all my homelab to the .internal domain, as I explained in a previous post, the DNS queries for this domain were not working.

$ nslookup printer.internal
Server:         127.0.0.53
Address:        127.0.0.53#53

** server can't find printer.internal: NXDOMAIN

These DNS entries are defined in my local DNS, two Adguard Home services running on my network. I needed to redirect these kinds of queries to the local DNS servers instead of using the quad9 one.

This configuration needs to be implemented for each trusted home network connection, given that the .internal services are only accessible from my home network.

Security Note: Queries for .internal domains will not be encrypted since we disable DoT for this connection. This is acceptable for home networks but ensure you only configure this for trusted networks.

Step 1: Connect to your home network

Step 2: Get the name of the active connection.

$ nmcli con show --active
NAME                         UUID                                  TYPE      DEVICE          
aetas                        95783eb7-4513-4b80-a6b4-ada6541034b2  wifi      wlp0s20f3 
lo                           770e3286-58c8-4e7e-88f6-22cf2c77c0c8  loopback  lo              

Step 3: Configure the connection

$ nmcli con mod "aetas" ipv4.dns-search "~internal"
$ nmcli con mod "aetas" connection.dns-over-tls no

I have added ~internal domain as DNS domain, it will redirect .internal DNS queries to this connection. It disables DoT for this connection, given that my local DNS are using just plain DNS (over port 53).

Step 4: Re-connect to apply the changes

$ nmcli con up "aetas"

Note: If you have multiple home network connections (different WiFi SSIDs or Ethernet connections), repeat Steps 2-4 for each one.

Step 5: Check if .internal works

nslookup printer.internal        
Server:         127.0.0.53
Address:        127.0.0.53#53

Non-authoritative answer:
Name:   printer.internal
Address: 192.168.1.23

Now all the .internal DNS queries are resolved by my local DNS while the rest are using quad9 DNS over DoT.

Step 6: Verify DoT is still working for other domains

To ensure that non-.internal domains are still using encrypted DNS, verify the DoT status:

$ dig +short txt proto.on.quad9.net.                              
"dot"

If you see "dot", it confirms that your regular DNS queries are still encrypted via DNS over TLS.

Wrapping up

I’ve included this configuration in my dotfiles repository

  • DNS_Over_TLS.sh is the utility to enable/disable the DoT
  • DNS_internal_domains.sh is the utility to configure the active network to enable .internal resolution.

Enjoy!