What are Resolvers?

In asyncdns, Resolvers are the objects that are responsible for taking Query objects and returning Reply objects corresponding to those queries.

Resolvers don’t derive from a single base class, as some of them work quite differently to others. Instead, they all implement the following two methods:

close()

Cancel all in-progress lookups and shut down the resolver.

lookup(query)
Parameters:query – The Query to process.
Retval:An asyncio.Future that will complete with a Reply.

Resolvers are guaranteed to cancel lookups that are in progress when the resolver itself is destroyed. Active lookups do not keep a resolver alive.

Individual resolvers may support additional parameters for their lookup() method, but those parameters are generally specific to the workings of the resolver in question.

Resolver

class Resolver

The core DNS resolver. This class holds all of the code to perform normal DNS queries, including recursive resolution, and maintains its own request cache, so that repeatedly querying for the same record won’t result in unnecessary network traffic or delay.

lookup(query, servers=None, should_cache=True,
recursive=False, prefer_ipv6=False, force_tcp=False)

Perform a DNS lookup.

Parameters:
  • query – The Query to resolve.
  • servers – See discussion below.
  • should_cache – Setting this to False disables the Resolver cache.
  • recursive – Whether to perform recursive lookups.
  • prefer_ipv6 – When doing recursive lookup, prefer servers that talk over IPv6.
  • force_tcp – Prevents the resolver from using UDP for queries that are short enough to fit.
Retval:

An asyncio.Future that will complete with a Reply.

The servers parameter can be:

  • An (address, port) tuple.
  • A list of (address, port) tuples, which will be used randomly.
  • An iterable of some sort that yields (address, port) tuples. Note that if the iterable raises StopIteration, any in-progress queries will fail with the StopIteration exception.
  • None, in which case the resolver will be recursive (regardless of the setting of the recursive parameter) and will start with the global root servers. We recommend not using this feature unless absolutely necessary, as it puts additional load on the root servers and it’s usually better to talk to your own nameserver or use one provided by your ISP or infrastructure platform.

asyncdns provides two useful iterables, RandomServer and RoundRobinServer, both of which provide an infinite stream of tuples given a list of server addresses.

flush_cache()

Flushes the resolver’s cache.

HostsResolver

class HostsResolver

Resolves names using the contents of /etc/hosts (or, on Windows, \Windows\System32\drivers\etc\hosts).

lookup(query)
Parameters:query – The Query to resolve.
Retval:An asyncio.Future that will complete with a Reply.

This method only supports A, AAAA and PTR queries. In addition to names listed in /etc/hosts, it knows about the .in-addr.arpa and .ip6.arpa pseudo-zones.

The HostsResolver will automatically re-read /etc/hosts if it has changed, but only if the last time it was read was more than 30 seconds ago.

MulticastResolver

class MulticastResolver

Resolves queries using Multicast DNS (aka MDNS). You don’t need to have Apple’s mdnsResponder software installed to use this - it will work on any system that can run Python and that supports IP multicast.

lookup(query, use_ipv6=False, unicast_reply=False)
Parameters:
  • query – The Query to resolve.
  • use_ipv6 – Whether to multicast using IPv6 or not. The default is to use IPv4.
  • unicast_reply – Whether to request that the reply be sent via unicast. This is intended to reduce multicast traffic.
Retval:

An asyncio.Future that will complete with a Reply.

SystemResolver

SystemResolver is actually a “class cluster”, in that there are separate implementations for Darwin/Mac OS X/macOS, Windows, and generic UNIX/Linux. The idea of SystemResolver is that it works like Resolver, but uses the system configured nameservers (and will automatically update its list of nameservers should the system configuration change).

There are some limitations here: the UNIX/Linux generic implementation works by reading /etc/resolv.conf, so any other configuration mechanism that might be in use will be ignored, while the Windows version uses Windows APIs that appear to be limited to returning IPv4 nameservers only. On Windows, there doesn’t seem to be a mechanism to spot changes to the configuration, so we re-read it at most once every 30 seconds; on UNIX/Linux, we watch the timestamp on /etc/resolv.conf, again, at most once every 30 seconds. Some people have suggested using res_ninit() on UNIX rather than directly reading /etc/resolv.conf; that’s certainly a possibility, but if /etc/resolv.conf isn’t being used to configure the nameservers, we’d end up in the same situation as on Windows, where we have no way to tell if the server settings have been updated.

class SystemResolver
lookup(query, servers=None, should_cache=True,
recursive=False, prefer_ipv6=False, force_tcp=False)

Perform a DNS lookup.

Parameters:
  • query – The Query to resolve.
  • should_cache – Setting this to False disables the Resolver cache.
  • recursive – Whether to perform recursive lookups.
  • prefer_ipv6 – When doing recursive lookup, prefer servers that talk over IPv6.
  • force_tcp – Prevents the resolver from using UDP for queries that are short enough to fit.
Retval:

An asyncio.Future that will complete with a Reply.

SmartResolver

SmartResolver is a convenience class that accepts a query and determines which of the other resolvers to use to process it. Specifically:

  • It first tries HostsResolver, which means the hosts file can override resolution the way people expect.
  • If that fails and the query is for a name ending .local, it uses MulticastResolver.
  • Otherwise, it uses SystemResolver.

N.B. Pay attention to the security implications of using MulticastResolver here; if you are using a server platform where multicast isn’t appropriately restricted, this could open up a security hole that causes you to send data to an attacker’s system instead of the one you wanted to.