Hardened DNS With Tor & Local Caching

Jan. 3, 2024 [hardening] [privacy-security] [guides] [libre] [technology]

The industry has been struggling with how to handle securing DNS, an original protocol designed without encryption in mind, which is responsible for informing your computer which IPs map to any domain name. This creates a problem in which any observer between you and the resolver can see all lookups your system makes. Additionally, you place complete trust in the resolver not to manipulate or misdirect domain name responses. Browsers have taken to sending DNS requests over HTTPS which solves only one aspect of DNS privacy but shifts trust over to new potential bad actors. Key things which need to be added to DNS to fix its security and privacy shortcomings include authenticity (DNSSEC), transport encryption (TLS, HTTPS, etc) and trustless resolution with recursion.

Unfortunately, not all three of these areas can be addressed by current solutions at the same time, so we will need to settle for picking two. Root name servers do not yet support encryption with their operators citing hesitancy to be first in adopting relatively immature solutions.

I have devised a DNS buildout which works around these limitations to provide robust, trustworthy, anonymized DNS resolution. In overview, it has two main routes to traverse for DNS lookups, both of which encrypt requests outbound from your computer.

Layout of anonymized caching DNS

We want to start by making sure Tor is installed, which should be the case if you already setup the metasearch solution earlier.

Now, assign a DNS port in your torrc. Append the following to /etc/torrc:


Then restart Tor:

systemctl restart tor

You should see that requests made out through should now resolve. I recommend testing with the dig utility from the dnsutils package:

dig @ www.google.com

If it works, the ANSWER SECTION should have a populated IP address. The Query Time will probably take 100 milliseconds or more.

DNS lookup over Tor

Now install the dnsmasq caching DNS server through apt and edit the file at /etc/dnsmasq.conf to change the following sections:

listen-address (INCOMING queries)

server=       (OUTGOING referrals)

no-poll         (no-resolve & no-poll make dnsmasq ignore resolv.conf and use servers specified in dnsmasq.conf)


min-cache-ttl=1800  (Forces queries to remain cached for half hour. 3600 for full hour.)

Then restart dnsmasq

systemctl restart dnsmasq

You may need to restart the session if you receive errors about “port binding already in use”.

Now test this address with dig also:

dig @ www.google.com

At first, it will take 100-300 milliseconds like before. But all subsequent tries for up to a half hour should result in 0 millisecond Query time! This is because dnsmasq is saving the result locally and preventing your computer from reaching out over the network again for the same information.
UFO takes what it wants

Lookup with DNSmasq and Tor DNS

Now, technically, you can use this alone and it would work okay. But the only issue is that in order to connect to a Tor circuit when starting up, you computer needs to first be able to resolve domain names in order to find a Tor node. A catch 22! So a backup is needed.

Install Stubby through apt and edit the file at /etc/stubby/stubby.yml to change to


The reason for changing the address is that we do not want hosts entries which null route bad domains to actually resolve, which will be covered in an upcoming hosts blacklisting guide. Also make sure that GETDNS_AUTHENTICATION_REQUIRED is enabled, which it should be by default:


There are default resolvers setup through the getdnsapi project that support DNS over TLS. Others may be enabled but just make sure that they support TLS encryption. Then:

systemctl restart stubby

Also test the stubby daemon with dig to confirm it is working:

dig @ www.example.com

Lastly, it is time to update dhclient to use these local servers. Edit /etc/dhcp/dhclient.conf to contain:

supersede domain-name-servers;
append domain-name-servers;

The section under send-hostname = gethostname(); can be reduced to:

request subnet-mask, broadcast-address, routers, interface-mtu;

Then reboot or restart dhclient:

dhclient -r

Now all DNS requests should be sending through to Dnsmasq to Tor by default. If a query fails through this, it will go to Stubby. Additonal changes may be required depending on your destop environment and distro. For example, network manager should be edited so that it doesn’t overwrite your resolv.conf. /etc/NetworkManager/NetworkManager.conf should have:


Also, Firefox should to be instructed to use system DNS rather than Mozilla’s implementation of DNS over HTTPS. Otherwise, cloudflare will continue getting a detailed log of all your web activity. As covered in Browser Hardening, the about:config setting for this is:

network.trr.mode = 5

Some minutia to be aware of:

This completes a strong, anonymous and sometimes just private DNS system. Things will likely change as root name servers begin to support encryption but this is the best I can think of for now. More to follow on domain name lookup solutions as things develop.