Ultimate DNS Setup: How to Reduce, Secure & Encrypt DNS Traffic

Domain Name Service (DNS) is one of the building blocks of the Internet, yet people pay very little attention to it. Using it optimally, can help you run much much more faster but also more secure.

In this tutorial, I will show you how to reduce your DNS queries and secure them using encryption. This is all about how you can secure your Mac, by switching on default DNS security options and running software such as DNSmasq.

Setting up /etc/hosts correctly

Very few people make the most out of the /etc/hosts file.

/etc/hosts is the file that is read before a DNS query is made. In it, there are domain name entries mapped to their IP addresses.

In our case, /etc/hosts can be well used to block DNS queries, such as the ones performed by malware, advertisement tracking and other unwanted domains.

To block a domain, simply add an entry unwanted-domain.com to the file. The points to an impossible path, resulting in a dropped query.

In order to get setup, let's quickly add an extensive ad and malware blocking list to our file.

curl "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts" | sudo tee -a /etc/hosts

This downloads one blacklist hosted by StevenBlack and automatically appends it to /etc/hosts. Other blacklists can be found here.

$ wc -l /etc/hosts
41090 /etc/hosts

As we can see, we have now successfully blacklisted ~40.000 domain names. The beauty about it? Even an anti-ad blocker script can't notice it.

Improving Speed by Caching DNS Queries

The next step is to use DNSmasq, which is basically a local DNS server, that caches your queries, prevents upstreaming queries for unqualified names, and blocks entire TLDs. This is also the first building block for encrypting your queries, using DNSCrypt, later on.

Install DNSMasq on Mac

The best way to install DNSmasq is through brew. In case you haven't downloaded brew, go ahead and install it.

$ brew install dnsmasq
$ cp /usr/local/opt/dnsmasq/dnsmasq.conf.example /usr/local/etc/dnsmasq.conf

Edit the configuration:

$ vim /usr/local/etc/dnsmasq.conf

Read through the configuration. Here is what I recommend:

# Forward queries to DNSCrypt on localhost port 5355

# Never forward plain names

# Examples of blocking TLDs or subdomains

# Never forward addresses in the non-routed address spaces

# Reject private addresses from upstream nameservers

# Query servers in order

# Set the size of the cache
# The default is to keep 150 hostnames

# Optional logging directives

# Uncomment to log all queries

Then start the program using sudo – it needs sudo to bind itself to a priviledged port (53):

$ sudo brew services start dnsmasq

Now you need to tell the operating system to use DNSmasq instead of relying on an external DNS server. For this you need to open System Preferences > Network, selecting the active interface and click on Advanced. Select the tab DNS, click on + and enter
If you want to go all console, enter this:

$ sudo networksetup -setdnsservers "Wi-Fi"

Make sure DNSmasq is correctly configured:

$ scutil --dns
DNS configuration

resolver #1
nameserver[0] :
flags    : Request A records, Request AAAA records
Reachable, Local Address, Directly Reachable Address
$ networksetup -getdnsservers "Wi-Fi"

Note If you are using DNSmasq with a VPN, your VPN software might just override your DNS settings on connecting. This happens to me. I still haven't found the optimal solution myself, but more on the topic can be found here.

Setting up DNSCrypt

DNScrypt will encrypt all of traffic to DNS servers.

To install it use brew:

$ brew install dnscrypt-proxy

Now you need to find the homebrew.mxcl.dnscrypt-proxy.plist file, which I found either under /Users/julius/homebrew/Cellar/dnscrypt-proxy/1.7.0/ or /usr/local/opt/dnscrypt-proxy.

If you still can't find it, search using find:

$ find / -name homebrew.mxcl.dnscrypt-proxy.plist

Open it to make sure it includes the .conf file.

<!DOCTYPE plist PUBLIC "-/Apple/DTD PLIST 1.0/EN" "http:/www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">

Find the line containing the .conf string, in my example <string>/usr/local/etc/dnscrypt-proxy.conf</string>. Edit the file, make sure it includes the following:

## Full path to the list of available DNSCrypt resolvers
ResolversList /usr/local/opt/dnscrypt-proxy/share/dnscrypt-proxy/dnscrypt-resolvers.csv

## This is actually the Resolver that should be used; should be one of those contained in the list.
ResolverName random

## Local address and port to listen to.

## Run the proxy as a background process.
Daemonize yes

## Cache DNS responses to avoid outgoing traffic when the same queries are repeated multiple times in a row. 
LocalCache on

## Run the server as a less-privileged system user.
User nobody

Now you are all setup. Save the file and start the proxy server.

$ sudo brew services start dnscrypt-proxy

Check that it's actually bound to port 5355 and that the process is truly running:

$ sudo lsof -Pni UDP:5355
dnscrypt- 39324 nobody    6u  IPv4 0x469e69288063ae1f      0t0  UDP
$ ps A | grep dnscrypt
39324   ??  Ss     0:00.01 /usr/local/opt/dnscrypt-proxy/sbin/dnscrypt-proxy /usr/local/etc/dnscrypt-proxy.conf

Confirm then that the outgoing DNS traffic is encrypted:

$ sudo tcpdump -qtni en0
IP > UDP, length 512
IP > UDP, length 368

dig +short -x

Risks Mitigated

By using DNSmasq in combination with DNScrypt we reduce the following risks:

  • Man in the Middle Attacks (such as DNS spoofing)
  • Eavesdropping

Not only do we reduce risks, we also improve speed by caching results locally. Thus, resulting in better privacy online.