Your corporate telephone directory queryable via the DNS? Sure, I’ve shown you how to do it in Perl using Stanford::DNSserver, but I was recently asked wether a separate authoritative server really was required. An authoritative server isn’t required if you use Unbound.
- Authoritative responses to queries can be generated on the fly. (This is the functionality we’ll be using here.)
- Responses to queries obtained from the public DNS can be modified before being returned to the DNS client. This could be interesting, say, to increase or lower the TTL of a particular set of records, or to lie.
- Packets can be logged.
The first item is particularly interesting because we can obtain data from the myriad of sources Python and its modules have to offer: do you want to build a customized DNS blacklist that uses a fast database, Redis, say, as a back-end? Want to query Twitter statuses over DNS, or provide a DNS gateway to a REST weather API? Do you have a parts database you want exposed over the DNS? Any and all of these and more are possible using Unbound, some Python and a bit of imagination.
I’m going to show you how to gateway a DNS query to an LDAP search result. This was a real requirement years ago, and at the time I wrote something that would allow me to query the DNS for a user’s unique identifier and get back her workstation’s IP address, telephone number, name, and e-mail address. The module I’m showing you here delivers a telephone number only, but you’ll quickly get the idea and be able to expand on it at your heart’s content.
My Telephone directory module is based on the response generation example.
It provides DNS
TXT records as responses to queries of the form
first.last.tele in my arbitrarily chosen top-level domain
.tele. In the former example, all LDAP entries for the surname are searched,
in the latter case LDAP entries for common name
Here’s a sample LDAP entry in my directory:
Let me query for Jane’s number; I know her first and surnames, so I use both:
Note how the reply is authoritative (flags
Specifying a surname only, I get a list of all
jolie* in the LDAP
directory. (Careful: a search for
*.tele will also work!)
This data is provided by a recursive Unbound server running on my workstation or on a central DNS server your organization may have, and it logs the LDAP search filter used:
And here is the source code for the module; keep the structure documentation handy. Each python module must define four functions:
initfunction is invoked once at Unbound startup, when our module is loaded. It is here we can connect to databases, initialize data, etc.
cfgis a class which provides attributes on Unbound configured settings. For example, I can determine the name of the DLV trust anchor file so:
deinitis also invoked once, when our module is unloaded.
- The documentation states, that
inform_superis called when the “querystate is finished”. I’ve never seen this function invoked in my code.
operatefunction is where the action happens; this function handles DNS queries received by the server. It accepts a new query or handles a pending query.
As far as Unbound’s configuration goes, adding a Python module script is
easy. I configure
python in the
module-config and add the my script’s path
When Unbound processes a DNS query it calls the modules listed in
from left to right. In our case the validator doesn’t have an answer (it only
knows how to validate a reply) so the python module gets the query. It can either
generate a response or pass the event on to the iterator, the last module in the list.
When our python module is called with
MODULE_EVENT_PASS it means the event has
already been handled by the validator.