# Scanning for DNS resolvers

For a research project I’m working on, it has become necessary to scan potentially large IPv4 prefixes in order to find any DNS revolvers that I can and classify them as either open (accepting queries from anyone) or closed.

Disclaimer: This is a form of port scanning and thus has associated ethical and legal considerations. Use it at your own risk.

This project is available on GitHub: jpverkamp/dnsscan

The idea is pretty simple. I want to be able to do something like this:

\$ ./dnsscan.py 8.8.4.4/30

8.8.4.4,open


(8.8.4.4 is one of Google’s Public DNS servers.)

What do we need to do to get there? Well, most of the code is framework, parsing command line arguments and looping over IP prefixes. The interesting part comes down to using the dnspython library to make DNS requests to any arbitrary IP.

It’s not actually straightforward how to do that (by default dnspython will read your /etc/resolv.conf file), but digging a bit into the documentation, I found that you can change the nameservers property to get what I’m looking for. Something like this:

resolver = dns.resolver.Resolver()
for ip in prefix_to_ips(prefix):
resolver.nameservers = [ip]


That way you will get all of the default configuration, but you can swap out nameservers.

After that, you have to process the response. Basically, there are three possible responses:

• You get an answer: this is an open resolver
• You contact the server, but it doesn’t give you an IP: this is a resolver, but it’s closed
• The connection times out: this isn’t a resolver (or there’s a firewall, etc)

I can process these to output what we need:

for ip in prefix_to_ips(prefix):
resolver.nameservers = [ip]

# If we get an answer, it's open
try:
print '%s,open' % (ip)

# NoAnswer: Contacted a server but didn't get a valid response
# NoNameservers: Couldn't get a valid answer from any of the nameservers
# These probably mean it's closed