Knot Resolver 1.1.0

Knot Resolver 1.1.0 is out and it brings several notable features.

DNS over TLS

DNS over TLS is the number one emerging technology to ensure privacy in the DNS. DNS Privacy Working Group has finished the specification this year as RFC 7858. Knot Resolver supports server-side DNS over TLS, so you can use DNS over TLS (such as kdig from Knot DNS 2.3.0) to connect to Knot Resolver over port 853.

The DNS over TLS implementation in the Knot Resolver is a result of cooperation between CZ.NIC and Daniel Kahn Gillmor during the IETF Hackathon.

DNS Cookies

DNS Cookies are a lightweight DNS transaction security mechanism that provides limited protection to DNS servers and clients against a variety of increasingly common denial-of-service and amplification/forgery or cache poisoning attacks by off-path attackers. DNS Cookies is specified in RFC 7873.

DNS Cookie is an EDNS(0) Option that adds shared pseudorandom data that could be used to mitigate source address spoofing attacks that are commonly used in Denial of Service Attacks.

Better forked model

Knot Resolver 1.0.0 brought a lot of possibilities, but also unnecessary complexity in some places. Take for example the forking model. You can ask the daemon to fork itself into N independent processes, which gives you more performance. But now you have N daemons to worry about, pushing N metrics and having N configuration interfaces. Knot Resolver 1.1.0 that and you can now run expressions over all workers:

$ nc -U tty/*
> map ''
[1] => 0
[2] => 2
[3] => 1

Modules like stats leverage that and aggregate metrics from all workers before pushing, and leader worker is the only one pushing them. Spoiler – this is how forked mode looks like on web interface, leader process can now see workers:

The forked mode now works on OS X, older Linux and BSDs too if you run it under supervisor that manages open sockets.

HTTP/2 interface

There is a new quite exciting module relying on worker IPC – an HTTP/2 interface. It supports TLS with ephemeral certificates by default, websockets, reprioritisation, push, and all that stuff. While TTY control is akin to getting “root shell” to daemon, this gives other modules the power to export fine-grained control to functionality over RESTful APIs. For example, allow user X to add only firewall rules only for destination IP assigned to him, or let user Y enable prefetching on selected zones. Modules can expose RESTful API in a few lines of code – see examples in the documentation.

$ curl -k https://localhost:8053/stats | jq .
  "worker.queries": 7620,
  "answer.nxdomain": 595,
  "answer.noerror": 5811,

The HTTP/2 interface also has endpoint for exposing streaming websockets from modules, can listen on split public-facing and internal-facing interfaces and more – read the docs and examples.


In addition to graphite module, the HTTP/2 also exports metrics endpoint for Prometheus pull-style metrics. Great for setting up alerts!

$ curl -k https://localhost:8054/metrics
# TYPE worker_queries counter
worker_queries 7660.000000
# TYPE answer_nxdomain counter
answer_nxdomain 595.000000
# TYPE worker_rss counter
worker_rss 135393280.000000

Web interface

The HTTP/2 module effectively deprecates the previous tinyweb experiment. Compared to that – other modules can add components on page, all static assets are served from memory (nothing touches disk), it’s very efficient. The page is built with Bootstrap3 and bundles several libraries for graphing and input, although nothing prevents you from rolling React components in own modules.

It has interactive dashboard with metrics, up to 120 datapoints is kept in server for short-term history purposes (for more, you should use either Graphite-compatible TSDB or Prometheus).

Metrics graph

The HTTP/2 module supports newer MaxMind DB format (GeoIP2/GeoLite2), including cities. You can now see which authoritative servers is resolver choosing and observe latency.


DNS Firewall

The 1.0 introduced policy & views modules. The 1.1 builds on top of that and expands it with an iptables-like interface over it for easy filtering – the DNS firewall.

> daf.add 'qname = deny'
> daf.add 'qname ~ AND src = deny'

It can however do much more than block, drop or force TCP. For example rerouting address ranges found in answers elsewhere – this example rewrites every A record matching to 127.0.0.x. This is superuseful in blocking malicious IP ranges, regardless of their domain name.

> daf.add 'src = reroute'

Another thing it can do is to rewrite specific records. Following will rewrite all AAAA records with ::1, effectively blocking whole domains. The rule is also source-subnet specific, it will only apply for queries coming from localhost.

daf.add 'src = rewrite AAAA ::1'

Forwarding & mirroring

It can also forward queries matching given pattern to another recursor, or mirror part of traffic to given address. This could be used to sniff part of queries and send them to traffic analysis appliance, that could in turn automatically generate rules to mitigate attacks.

> daf.add 'qname = forward`
> daf.add 'qname ~ mirror'

The firewall rules trigger either before resolving query or after resolution, this way it never polutes resolver cache so it’s safe to add, suspend and delete rules in real time. The module has RESTful interface too, and more – peek at the documentation.

There is also a web interface for managing these rules, it’s super easy to add new rules and track matches.

The firewall module ties everything from inter-worker IPC to HTTP/2 together into a nice and useful package. Thanks to LuaJIT, the rules are compiled into filter functions, and then in turn compiled to machine code during execution for very efficient filtering, which is something that wouldn’t be possible in statically compiled language.

There you have it, that’s HTTP/2 and DNS Firewall in the 1.1 release. See the Knot Resolver modules documentation for examples, guides and documentation. If you’re a package maintainer, be sure to check the module pages for dependencies (the excellent lua-http and optional lua-mmdb).

As always, Knot Resolver respects “batteries included, but optional” philosophy. Everything described here is optional and is not loaded at all unless specifically configured.

Socket-activation via systemd

Knot Resolver can now run in completely unprivileged mode thanks to socket activation. All sockets (including TLS and control socket) are binded by systemd and passed to Knot Resolver via named systemd file descriptors. This has been already integrated into Debian package or you can use upstream systemd units.


Leave a comment