Table of Contents
In May 2021, I created a custom authoritative DNS server for research purposes; I currently have it running on 2 different servers (one in England, and one in The US). I have a domain configured to use these servers so any DNS lookups for that domain come to my servers to be resolved.
You can view the documentation page here. This project is still in very early development and some features may not work reliably or may change without warning.
In July 2021, I created a Python script which performs some DNS queries to detect certain types of DNS tampering and misconfigurations
As of August 2021, I have decided to stop development of this project and have taken the servers offline.
Some DNS resolvers and caches will modify the TTL value which the authoritative DNS servers provide. For example, Quad9 (126.96.36.199) seems to set the TTL to 5 seconds whenever a record with a 0-5 TTL is returned. Cloudflare DNS (188.8.131.52) never seems to modify the TTL but will return cached data for zero-TTL records for around a second after the most recent lookup.
In order to test for this behaviour, it is helpful to be able to customise the TTL the authoritative DNS server returns. The left-most subdomain in the query is converted to a number (if possible) and used as the TTL value; this means a query like 0.dapi.jhewittapi.com would return a TTL of zero and 10.dapi.jhewittapi.com would be a 10 second TTL.
Custom IP Address Responses
When performing security research into a service, it is sometimes helpful to have a domain which returns local addresses (127.0.0.1, 192.168.x.x, 10.x.x.x, etc). Queries can be constructed with an IP address in the subdomain and that IP will be returned when queried.
For example, cip-192-168-1-1.dapi.jhewittapi.com would return an A record equal to 192.168.1.1 (or any other specified IPv4 address).
In some situations, this can be used to trick a service into connecting to another service on its own private network. This is because many developers will prevent their application from connecting to an IP address directly but will blindly accept any IP provided by a DNS lookup.
I found a website uptime checker which refused to test the uptime of “localhost”, “127.0.0.1” etc but happily connected to itself when I tested cip-127-0-0-1.dapi.jhewittapi.com.
This can also be used to test if a DNS resolver will modify the returned IP address for any reason.
DNS Resolver Lookup
There are many public services which will tell you who is resolving your DNS queries. These services are useful because they can tell you if your DNS queries are “leaking” when using a VPN; eg, your DNS queries may be bypassing your VPN and going directly to your usual DNS resolver which means your ISP can still monitor your VPN activities.
I added the same type of test directly into my DNS server so you can make a simple query to determine who your DNS resolver is. For example, asking Cloudflare public DNS (184.108.40.206) to resolve test.dapi.jhewittapi.com returned “220.127.116.11” on my home network; at the time of writing, that IP address belonged to Cloudflare's London datacenter.
If I perform the same lookup using my default resolver (a Pi-Hole installation on my network), the returned address is “18.104.22.168”; at the time of writing, that IP address belonged to nextdns.io which is a DNS resolver I am currently testing. My Pi-Hole installation will forward queries to the fastest resolver in a list of 3 servers so this shows that right now nextdns.io is being used by Pi-Hole. If I make the same query again in 10 minutes, I may get an IP belonging to another resolver in my Pi-Hole list.
I added the ability to create custom-length CNAME chains to see how various DNS resolvers would react. By using the subdomains “rtcnl.cnl-40” my server is instructed to return a CNAME equal to the current requested domain but with the number decremented by 1. This means that rtcnl.cnl-40 will be requested, then rtcnl.cnl-39, rtcnl.cnl-38… rtcnl.cnl-1
Once the counter reaches 0, the CNAME looping parts of the query are removed and the usual rules apply (such as returning a custom IP address). See the image below for an example of this query in use:
All queries are logged along with which IP performed the lookup. This means that a random subdomain can be generated, given to a service, and then looked up in the log later to see how the query was made.
This can be used to reveal the true IP of a server hiding behind a proxy (such as Cloudflare) in some limited situations. For example, I gave the following email address (with permission) to a registration form “[email protected]” and noticed the web server performed a DNS lookup directly as a basic email validity check. This revealed the true IP of the web server despite being behind Cloudflare. Most servers will use a public DNS resolver (such as Google DNS 22.214.171.124) but occasionally they might query my nameservers directly.
This test can also be used to check the approximate geographical region of the server. If the server uses 126.96.36.199 as their resolver and the log shows a request from a Google London IP address, you can be reasonably sure that the server is located in England (or is proxying its connections through England).
I have started working on the HTTP API which now allows basic stats to be returned about the entries in the logs. For example, it is possible to visualise the types of queries received in Grafana as shown below: