A DNSSEC-validating, NTA-capable, Lua-configured, DNS resolver/recursor with RFC5011 support backed by LMDB? Yes, it was announced yesterday, and I just had to take a look, and I want to thank Marek Vavrusa for some hand-holding.
First off, the documentation for the Knot Resolver is impressive and reads well. Building the Resolver is easy enough and currently involves a few
./configure invocations on a number of dependencies, including libknot. Packages are in the making, and our friends at CZ.NIC have also got an Ansible playbook for building and installing it.
After the ubiquitious
make install, I create an empty directory and launch the server, which is called
kresd, passing it a the path to a file containing the root DNSKEY record which kresd uses to validate DNSSEC records. (Knot should provide a utility such as Unbound’s unbound-anchor to obtain that securely.)
What we see is the CLI prompt from which we issue commands to kresd, update settings, etc. This is, in fact, a Lua interpreter which is running.
According to the documentation, the key file we specify on start will roll according to RFC 5011 semantics, though I haven’t tested it; I’m still recuperating from my last tests of RFC 5011.
Kresd will fork n times with the
-f option, in which case it doesn’t bring up the interactive console, but we can connect to a console if we know the PID:
After adding that hint module, I obtain:
which comes right out of
/etc/hosts. (The hints module does that for local data, but I strongly disagree with the
+AD flag because that was not signed data. Update: this is being changed to report
+AA which is sensible.)
There are a number of resolver modules for collecting statistics, for query policies, views, and caching. For example, the memcached module uses memcached (or memcacheDB, which is backed by LMDB) to manage a cache shared by multiple Knot DNS Resolvers, and the redis module does that with Redis. The prefetch module can track records which are about to expire and fetch them in advance, i.e. before their TTL runs out. The graphite module can send metrics to Graphite or, preferably, to InfluxDB and Grafana.
For configuration, kresd can use the etcd module which watches for configuration changes with etcd – very useful for configuring a large deployment of Resolvers.
As mentioned above, kresd’s configuration is in Lua, and as such we can use the full flexibility of the language and any external Lua modules we desire, to flexibilize (that’s a new word I invented not very long ago) our setup. An example copied from the documentation illustrates this.
Further examples include using
socket.http to download a “hot” LMDB cache database from a parent Resolver in order to avoid cold-starting this particular instance. The Knot DNS Resolver uses LMDB as a fast local cache if we don’t set up caching via one of the additional modules.
If a file called
config exists in rundir (which we specified above as
/var/kdns) the server reads that at startup. It is herein we specify a configuration for this server.
To Trust or Not To Trust
RFC 7646, Definition and Use of DNSSEC Negative Trust Anchors, specifies a method by which a resolver can be instructed to please not validate DNSSEC data for a particular zone because the resolver’s operator knows the data is bogus. (RFC 7646 is also the very first RFC to mention a blog post of mine; it’s in a footnote, but hey! :-)
These Negative Trust Anchors (NTA) are important. Consider the case of Comcast trying to fix the NASA.gov fiasco a few years ago: adding an NTA makes the resolver’s clients unaware that there are problems in as much as domains resolve albeit insecurely. It’s the operator’s responsibility to monitor the faulting zone and remove an NTA as soon as possible. (See also: Stéphane Bortzmeyer’s article on NTA (in French).)
The Knot DNS Resolver supports NTA. We create a Lua table with the names of the zones below which we want validation to be ignored. As soon as we set
trust_anchors.negative, kresd treats the zone as though it were unsigned.
I’m not sure whether this is on purpose or not, but I’m seeing NTA applied only on names which aren’t in the cache. If I set an NTA as above, the negative trust is applied only when the TTL of
jpmens.net expires. A workaround, at least at the moment, is to load the cachectl module and flush the cache:
Unfortunately this clears the whole cache. A
cachectl.clear(<name>) would be a useful addition. Update: beta #2 will allow
I think things like distributed caches (with Redis or memcached) will be something large operators are going to find very attractive. From the point of view configuration, the etcd module is brilliant as it allows central configuration without having to resort to Ansible & co, and the use of Lua as a configuration language (and partially internal – some of the modules are in Lua) is grand in terms of flexibility.
As soon as Knot DNS Recursor matures a bit, it would be good to see how it performs in comparison to the other two Open Source validating resolvers, BIND and Unbound, in a setup similar to the benchmark done for authoritative servers.
This is the first time I’ve looked at the Knot DNS Resolver, and the “package” seems to be quite complete.