While I usually use a VPN in public places like cafes, I don't always do on networks I trust more, like my home or University. Nearly all of my network traffic is encrypted thanks to HTTPS, so my DNS requests are the only plaintext data I sent out in the wild.

I've been using DNS-over-TLS (DoT) on my Android phone for nearly 2 years thanks to Android's native DoT support since version 9. After doing a little bit of research a while ago, I thought it would be a hassle to use an encrypted DNS protocol on my MacBook, but it turns out to be very simple.

Since macOS does not natively support DoH or DoT, I use dnscrypt-proxy, a DNS proxy written in Go by the great Frank Denis, which support DoH and DNSCrypt as you would expect.

DNSCrypt/dnscrypt-proxy
dnscrypt-proxy 2 - A flexible DNS proxy, with support for encrypted DNS protocols. - DNSCrypt/dnscrypt-proxy

It is available via Homebrew:

brew install dnscrypt-proxy

Once that's done you'll want to edit /usr/local/etc/dnscrypt-proxy.toml. Well, it will work out of the box, but I wanted to use a different resolver.

I want to filters ads and trackers at the DNS level so I use AdGuard. The id of this resolver is adguard-dns-doh. The whole list is available on the DNSCrypt website.

server_names = ['adguard-dns-doh']
I use Cloudflare as a fallback.

Let's see if dnscrypt-proxy can resolve domains:

[email protected] ~> dnscrypt-proxy -resolve angristan.xyz
Resolving [angristan.xyz]

Domain exists:  yes, 2 name servers found
Canonical name: angristan.xyz.
IP addresses:   104.18.39.46, 104.18.38.46, 2606:4700:30::6812:262e, 2606:4700:30::6812:272e
TXT records:    brave-ledger-verification=fd8f3a19fc8e501be7f76d277c8f88fff716c3cfa1833ed884d77bca83cb7881 v=spf1 include:_mailcust.gandi.net ip4:212.129.1.254 ip4:149.91.88.65 ip4:5.196.68.142 ip4:163.172.135.172 ip4:51.15.36.164 ip4:89.234.181.50 ~all google-site-verification=fNMfWdWJ_08h6_4aKxZBejZ3LXU5MtHXDV_hTfQ4vVQ keybase-site-verification=aET_nAgv7W-03TGJg06tSKXoXTWMvUyAO4VwBAzD1RI ca3-548d3f50aebe4077a2f55cc8f6ddebb8
Resolver IP:    207.148.93.221 (207.148.93.221.vultr.com.)

Now let's start the service and register it so that it will automatically start during the next boot:

brew services start dnscrypt-proxy

If you're using Wi-Fi, you can set the resolver from the command line:

networksetup -setdnsservers Wi-Fi 127.0.0.1

Otherwise, go the the system preferences and set it yourself.

Now, by issuing a simple dig we can see that 127.0.0.1 is able to resolve DNS queries.

[email protected] ~> dig

; <<>> DiG 9.10.6 <<>>
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 42178
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 14, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4048
;; QUESTION SECTION:
;.				IN	NS

;; ANSWER SECTION:
.			86382	IN	NS	f.root-servers.net.
.			86382	IN	NS	g.root-servers.net.
.			86382	IN	NS	h.root-servers.net.
.			86382	IN	NS	i.root-servers.net.
.			86382	IN	NS	j.root-servers.net.
.			86382	IN	NS	k.root-servers.net.
.			86382	IN	NS	l.root-servers.net.
.			86382	IN	NS	m.root-servers.net.
.			86382	IN	NS	a.root-servers.net.
.			86382	IN	NS	b.root-servers.net.
.			86382	IN	NS	c.root-servers.net.
.			86382	IN	NS	d.root-servers.net.
.			86382	IN	NS	e.root-servers.net.
.			86382	IN	RRSIG	NS 8 0 518400 20191120170000 20191107160000 22545 . P+NZ5s/BLv/MLMaZqNB5Otu2NZIoQLxaJKHK/wNH3Ikw93b67ZsO9pZ4 tqZG6AuKlevSvSLjoTAatT6OiKsLhQDuFb1OqjZPz3ezHJ8rdyybKg/Q AdBj37Pn5EcoYp4KOUBvP2TFZcCcSlIMA3J6cQY/4jPfosfciG1wyz0j dWbrh3VJUuZgPggR7YIhR+lleb5BKR3eNCkoI05JMwUO6osS36UoGo7a RGyCeQIVWrHtC4ZxLUFWf4QnMaPMBAi5rYx2YvrjdyrN9P68pGPHxa2q DrnBKg3VvODSmOB0REXGeFhzkhwAXhvEf1MsnHib7FR/iOUjAFjJ5Cyg qvz+RQ==

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Fri Nov 08 16:21:46 KST 2019
;; MSG SIZE  rcvd: 525

To see if all the queries are going through dnscrypt-proxy, you can stop the service and check that you're not able to resolve anything.

Congrats, your DNS queries are a little more private now.