DoH! (or: Securing Traffic with DNS over HTTPS)

A few weeks back I wrote about the FrankenMini – the Mac mini I assembled a la Tony Stark out of a box of scraps. Okay, Iron Man did his thing in a cave in the desert with a bunch of weaponry and I did mine in my garage with a couple of screwdrivers and a certain amount of swearing, but we both looked a little sickly and had uncool scruffy facial hair, so I’m calling it pretty much a dead heat.

I used to run a much nicer Mac mini as a file/web/whatever server in my home office, but switched that to a nice Synology Diskstation that’s synced to an identical unit in my downtown office, and with that in place I no longer had need of the nice Mac mini which went on down the road to a friend of mine. This, it turns out, was no great loss, as Apple has been steadily and methodically stripping functionality out of macOS Server for years, and as such there wasn’t a lot of tinkering possibility locked away in the thing.

But now I have this old, terrible, not nice-but-perfectly-serviceable Mac mini doing little except feeding the occasional print job to my 3D printer and sitting reproachfully on a workbench, so I thought I’d do something useful with it and implement DNS over HTTPS (or DoH if you don’t like a lot of typing. Which I don’t.)

Hmm? What’s DNS over HTTPS, I hear you say? Let me explain.

If you’re interested in a slightly higher level view of the basic mechanics of DNS – and I highly recommend you dip a toe into that water because it’s perfectly warm and not as full of monsters as you may expect – I’d encourage you to go look here at this excellent write up on cloudflare.com:

“How does DNS work?”

DNS is (to cut a tremendously, tremendously long story short) the way that your computer turns human-readable internet names (e.g., www.apple.com) into the actual IP addresses that your computer needs to get to a webpage (e.g., 23.15.137.53). It does this by reading what you type into, say your browser (although many, many things on your computer use DNS, a lot of which you wouldn’t think of and many that you’d never know about) and then sending that inquiry off to a DNS server (or more correctly a DNS resolver) – usually on the internet – that does the footwork and goes and queries other DNS servers to work out where it is you want to go.

But how does your computer know where the DNS server/resolver is? Well, the address of the DNS server/resolver is something that’s provided to your computer by whatever network your computer or device is connected to – your home router, or your mobile hotspot, or the coffee shop wifi network (back when we could go and sit in coffee shops, that is). Those networks assign your computer or device an address on their local network and a DNS server so that when you send a query out to the world at large to look at www.apple.com that network will know where you are to send that information back to you.

The internet as we know it only functions because of DNS, and the architecture of DNS is one of the great unsung marvels of the modern age. It’s not sexy or cool or attention-grabbing, but were it not for DNS there’d be no Google, or Amazon or Netflix or… well, you get the idea. Still, DNS dates back to 1983 and because it’s such a crucial part of the way that the modern world works, progress on things like security have been slow albeit steady. It’s not the kind of thing you can make major, paradigm-shifting changes to without breaking modern civilization very badly, which, I think we can mostly all agree, would be A Bad Thing.

The chief problem with DNS is that the resolver sits there, happily gathering information on what you’re sending it whether you like it or not. As a general point of principle it’s a little creepy that your ISP or whoever is providing you with the resolver knows what’s going in and out of your computer, but principle aside there are a lot of use cases where that’s data that you really don’t want getting out there. I’ve worked with clients who are doing contract work for the DoD, for example, and who aren’t thrilled that someone with a will and a relatively small amount of resources could theoretically sniff the traffic they’re sending to their DNS resolver. Happily there’s a way of stepping around that, which is where the FrankenMini™ steps in.

Cloudflare offers a fast, secure DNS resolver that encrypts traffic with TLS via HTTPS. In more normal English, HTTPS is the securely encrypted version of HTTP, which is in turn the protocol used to deliver web content over the internet. When you connect to a secure webpage – a bank or online store for example – you’re probably connecting via HTTPS. However, when your computer goes to initially send an inquiry to most DNS resolvers that inquiry is sent as an unencrypted HTTP request – in effect, your ISP can’t see what you’re doing on a secure website, but it can snoop on where you’re going.

Many modern browsers (Chrome, Edge, Brave, Firefox et al) already have DoH built in as options, but Safari does not. And that’s vexing. Additionally, there are other types of software than web browsers that also use DNS, and it’d be nice to be able to roll those protections over for those other pieces of software or services. Happily, Cloudflare has an option for that – the cloudflared client. If you install this onto your Mac then anything on that Mac will be able to use DoH. And if you make that Mac your DNS server then anything on your network will likewise automatically be able to use it, too.

So, on one hand I have a FrankenMini™ and in the other hand I have cloudflared. I think you can probably work out where this is going.

To business, then – setting up the FrankenMini™ to be a DNS server so that every DNS search is encrypted and nice and secure!

First, we’ll need a DNS server that we can run on the Mini, because otherwise there’ll be nothing for the devices on the network to use. I’m going to use dnsmasq because it’s open source, easy to configure, pretty well-documented and generally awesome. Once that’s in place I’m going to install cloudflared so that DNS requests that the Mini sends out are covered by DoH, and finally I’m going to tie those two things together so that DNS requests from computers/devices/whatever on my network come into the Mini via dnsmasq and the Mini then pushes those DNS requests out via cloudflared.

Installing dnsmasq and cloudflared is done via homebrew, thus:

brew install dnsmasq

…and then

brew install cloudflare/cloudflare/cloudflared

Once dnsmasq is installed the next step is to configure it to look at itself so that it can pass requests to the cloudflared client. This is done by digging into the dnsmasq configuration file at /usr/local/etc/dnsmasq.conf and then changing the default of #server=/localnet/192.168.0.1 to server=127.0.0.1#54

The next step is to configure cloudflared. Happily, Cloudflare has this covered on their site and it’s a simple matter of making a cloudflared directory in /usr/local/etc/ and then creating a file called config.ymlin that directory. You populate that file via a copy/paste job with a couple of minor tweaks – while normal, common-or-garden DNS runs on port 53 we’re telling dnsmasq to send inquiries out on port 54 and cloudflared to listen for requests on port 54 so that they can talk to each other privately and don’t start playing havoc with every other device on the network, and additionally we’re going to set a no-autoupdate flag:

no-autoupdate: true
proxy-dns: true
proxy-dns-port: 54
proxy-dns-upstream:
  - https://1.1.1.1/dns-query
  - https://1.0.0.1/dns-query

All that’s left is to make cloudflared and dnsmasq start when the computer boots up – the FrankenMini™ sips power like a little tiny baby bird, so it stays up and running 24/7, but on the off-chance that it needs rebooting it would be a hassle to have to remember to go into the garage (which, as mentioned in the main FrankenMini article is cold and chiefly filled with ghosts and rats) to manually go and kick-start the DNS server. Happily, cloudflared and dnsmasq include tools for this very purpose which you can install by typing the following into the terminal…

sudo cloudflared service install

…which will install a launchctl item at /Library/LaunchDaemons/com.cloudflared.plist, and…

sudo brew services start dnsmasq

…which will similarly enable dnsmasq

After that it’s simply a case of setting each device on your network to look at the IP address of the machine that’s running dnsmasq/cloudflared (or, in my case, setting my router up with that address so that every device connected to my network automatically gets that address).

One unanticipated but welcome discovery has been that Cloudflare’s DNS resolver (1.1.1.1) is astoundingly fast, and I don’t know about you but I’ll take fast and secure over slow and dreadful any day of the week…

Leave a Reply

Your email address will not be published. Required fields are marked *