hakk

software development, devops, and other drivel
Tree lined path

Detect Visitors DNS Provider

Recently I had bought a new router and was in the process of setting it up, during that process I started looking for various DNS-over-TLS and DNS-over-HTTPS providers. That’s when I came across NextDNS, on the setup page I saw the following:

NextDNS Setup page
NextDNS Setup page

I thought what!? How do they know that? After some investigation it all made sense, I’ll share what I found and a demo implementation.

Enter Dev Tools

The first place I start when investigating interesting finds such as this is my browsers trusty Developer Tools. Since this updated after the page loaded I went straight for the network tab to have a look. Something else I noticed along the way was that it was able to update in real time, very cool! Any back to digging through this to work out what’s going on.

After a quick scroll through I saw that it was making sending XMLHttpRequest (xhr) requests to unique subdomains in the form of https://<unique string>.test.nextdns.io/ which sends a JSON response back.

{
	"status": "unconfigured",
	"client": "xxx.x.xxx.xxx",
	"resolver": "xxx.xx.xx.xxx",
	"server": "anexia-ewr-1"
}

Following that it sends another request to this URL https://api.nextdns.io/resolver/xxx.xx.xx.xxx which determines the DNS provider being used and sends it back as a JSON response.

{"name":"Cloudflare"}

Digging a Little Deeper

After thinking about how I would go about developing a solution like this, I started wondering if the same DNS server was used for the main site and the test.nextdns.io domain. After querying the subdomain several times it seems they might use the same DNS servers that are used to query and serve records for their service, not sure on this assumption though. Anyway, it’s not Cloudflare that’s used as the NS for the top level nextdns.io.

Implementing a Demo

I decided to try my hand at creating something that could determine a visitors DNS provider as well. Fortunately, in this day and age, it’s easier than ever. Before this I had been working on creating my own DNS server to block ads and bad domains on my network, so I already had something of a head start for this.

Screenshot of the demo
Screenshot of the demo

Components

As this is just a demo, I decided to implement it as a monolithic program with the added feature of no tests.

First up, the HTTP server which will serve the up main page with a unique subdomain somewhere in it. I choose to use a CSS request to do this. The HTTP will also implement an API that will be queried after the page loads and will return the DNS provider in JSON.

Next, the DNS server. I choose to implement this as simple as possible. It will return a single IP for any incoming query, in my setup case it went to the default nginx server and actually returned a very basic CSS file.

The DNS server takes the remote IP address the that the lookup request came from and checks it against a CIDR range. For this demo I only used Cloudflare and NextDNS ranges, the ranges I had for NextDNS weren’t correct though but it still got the idea across for my purposes. From there it uses the unique subdomain as the key in a map and stores the name of the provider as the value. That is later used to populate the return JSON that the browser will call from the page served by the HTTP server.

If you’re interested to check out the code it’s available on GitHub.

Conclusion

As seen in this post tracking the user down to this level is actually quite easy. Doing something like this at scale would be a bit more difficult but obviously quite possible. This example of it’s use is fairly harmless, however it could be used to detect a DNS leak which if the visitor is going through a proxy could reveal the users actual location or be used for other nefarious purposes.