Michael Maclean

Evading broken DNS

Once upon a time I had quite a good ISP. They were fairly technically adept, had decent uptime, and would let you use whatever equipment you liked. Unfortunately a couple of years ago they were bought by my current ISP. They’re less friendly, require you to use their own equipment, do not provide a bridge mode on their routers, and finally they do an unfortunate thing where they will redirect any DNS queries I make on my internet connection to their own DNS resolvers. It doesn’t matter if you specify different ones, the resolver that responds is always going to be theirs.

This isn’t great from a privacy point of view; as DNS queries are generally transmitted in the clear, they can use their resolvers to get analytics on who’s doing what. I’ve been thinking about looking into their T&Cs to see what’s going on there but, despite 2020, I haven’t been sufficiently bored enough yet.

If you’re concerned that this might be happening to you, there are ways to test for it. One that’s quite easy to use is the DNS leak test.

As I’m using my connection for working from home I haven’t been in a hurry to go and invite the possibility of a couple of days of downtime in a failed switchover.

A couple of days ago everything seemed to be grinding to a halt. It seemed like there was something consuming a lot of bandwidth, but having unplugged everything it became apparent that the ISP’s DNS servers were just failing intermittently. As I write this, it’s been about 48 hours and they’re still doing it. Sadly, because of their cheeky firewall implementation, even if I configure my DHCP server to point DNS elsewhere, it still ends up on the failing resolvers. As is in-vogue these days, the status pages have not been updated to indicate that there’s any fault.

The fixes

So how can I work around this, if there’s no way to use another DNS service? There are two possibilities.

Browsers - DNS over HTTPS

Modern browsers (I’m using Firefox) have a feature built-in called DNS over HTTPS, or DoH. This routes DNS queries over an HTTPS-based transport, which appear to the ISP as standard HTTPS traffic, so they can’t really do much about it if you force it on in the browser’s settings.

Generally speaking, browsers will default to Cloudflare (1.1.1.1) or Google (8.8.8.8) for their DoH services. There is obviously a question of trust for using either of those, though for me it was better than what was available to me already.

Cloudflare’s pages on enabling DoH cover how to do it for desktop browsers.

Apparently DoH has made it into iOS 14 and macOS Big Sur. Paul Miller has a post on enabling it in iOS.

Everything else - DNS over TLS

That covers some web browsers, but it won’t fix the other devices on my network. As well as DNS over HTTPS, there is a specification for DNS over TLS. This, to me at least, feels like the kind of thing that should have been done a while ago. Rather than sending queries over an HTTP-based API, DoT just sends the same traditional DNS queries over a TLS-based encrypted and authenticated connection.

There’s a little bit of a chicken-and-egg thing with DoT. Because it’s TLS, and we want to use the trust features of the protocol, we want to be able to specify a hostname in the connection setup so that we can verify it in the same way as we do for HTTPS. However, we can’t resolve the hostname ourselves, so we need to specify the server’s IP and also the hostname we expect from it.

In practice this turned out to be pretty simple. I used CoreDNS. The configuration to create a new resolver forwarding everything to Cloudflare’s 1.1.1.1 service and caching it looks like this:

    . {
      forward . tls://1.1.1.1 {
          tls_servername tls.cloudflare-dns.com
        }
      cache
    }

As I’m running this on NixOS, the changes required to make it work amounted to adding the following to configuration.nix:

  services.coredns.enable = true;
  services.coredns.config = ''
    . {
      forward . tls://1.1.1.1 {
          tls_servername tls.cloudflare-dns.com
        }
      cache
    }
  '';

Followed by a quick sudo nixos-rebuild switch. I then had a functioning DNS resolver that could not be intercepted by my ISP, and I could slot its IP into my router’s DHCP options.

This all works great, although I’m probably going to move it onto another device for a more permanent solution. I’ve not yet played with Pi-Hole, and I do expect this could use the same trick.

NB: I don’t have a good reference for this, but I’ve seen people mention that lot of IoT devices such as set top boxes do not actually pay any attention to the DNS servers issued to them by DHCP. Some of them just use 8.8.8.8 all the time regardless of what the network is telling them to do. In this particular case with an actively hostile ISP, we couldn’t solve the problem for those devices without a router or similar doing something more clever than I’ve talked about here.