blog.robur.coop

The Robur cooperative blog.
Back to index

DNSvizor - run your own DHCP and DNS MirageOS unikernel - gets DNSsec support

2025-05-24

TL;DR: We have been working on DNSSEC the DNS layer, please let us know about strange DNS setups. You can also help us by sharing with us your dnsmasq configuration, so we can prioritize the configuration options to support.

We are continuing our work on DNSvizor (repository).

We finally managed to get our DNSSEC implementation, which we started to work on in 2019, and continued in 2022, ready for use in DNSvizor.

DNSSEC

The goal of DNSSEC is that anyone can verify that the DNS records published are those from the domain owner. A trust anchor for the root zone is publicly available, which is used to verify records.

There are several complications involved: a negative answer (this domain name does not exist, or no resource record of that type exists) does not carry any data in the DNS protocol - but nevertheless there needs to be a cryptographic signature (otherwise an attacker could always send a negative answer). To deal with this, originally only a NSEC resource record was invented, which lead to privacy issues (enumeration of all entries in the domain). Thereafter a so-called NSEC3 resource record was standardized, which applies hashing of the domain names (and thus enumeration is not easily applicable).

A DNSSEC aware resolver, as DNSvizor, needs to deal with domains that are signed properly, as well as with domains that do not use DNSSEC (and thus the domain one level up provides a NSEC or NSEC3 record that no DS/DNSKEY is available).

Deploying DNSSEC is not easy, and there are dedicated web pages recording outages and validation failures.

For DNSvizor, we adjusted the resolver algorithm to attempt to query for DS/DNSKEY records, implemented the cryptographic verification, and also handle client requests whether they would like to receive DNSSEC (DS/RRSIG/NSEC/NSEC3) resource records (EDNS DNSSEC OK, DO bit), disable the DNSSEC checking (Checking Disabled - CD bit), and expose the information whether the verification was successful (Authentic Data - AD bit).

We store the RRSIG records in our cache just next to the resource record - which is good since a RRSIG record alone is not of much use[1], and we only need a single lookup when a DNSSEC-aware client sends a request.

Developing the lookup algorithm (changes from the plain recursive resolver) was tricky, since loops need to be avoided, and it needs to be careful to eventually get to a reply to the client.

Since DNSSEC adds data to DNS replies, and DNS can be communicated over UDP, it is as well crucial to implement the upgrade-to-tcp portion if a truncated reply is received. DNSSEC support in authoritative name servers has been used for distributed Denial-of-service attacks, since it uses UDP (thus no connection, and IP packets can be faked). We mitigate that by having a small upper limit for UDP packets that we send out -- thus our DNS resolver won't be too useful as a DDoS host.

The work was done in several pull requests:

Especially the last hard bits were achieved in pair programming sessions at the MirageOS retreat and time thereafter.

If you want to read more on DNSSEC, there are some RFC documents:

Conclusion

DNSvizor provides DNS resolution and DHCP service for your network - and now uses DNSSEC. It already exists :). Please report issues you encounter and questions you may have. Also, if you use dnsmasq, please show us your configuration.

If you're interested in MirageOS and using it in your domain, don't hesitate to reach out to us (via eMail: team@robur.coop) - we're keen to deploy MirageOS and find more domains where it is useful.

Our work is only partially funded, we cross-fund our work by commercial contracts and public (EU) funding. We are part of a non-profit company, you can make a (in the EU tax-deductible) donation (select "DONATION robur" in the dropdown menu), or sponsor us via the GitHub sponsor button.

  1. When doing a dnssec query you get in the answer the relevant RRSIG records. That is, if you ask for the A record you will get an RRSIG record signing the A record. But for the same name there might be e.g. a MX record with a corresponding RRSIG record signing that - and you will not receive the RRSIG recording signing the MX record when querying for the A record. Thus we get an incomplete view of what RRSIG records exists and we should be careful with how we cache RRSIG records and what that entails. For example, we can't put the RRSIG record signing the A record in our cache and then assume because we have only that in our cache that there are no RRSIG records signing the MX record!

    What is also interesting is what happens when you query an authoritative name server for RRSIG records. It seems some implementations return all RRSIG records while at least another implementation refused answering that query. The recursive resolver in the cheap router we used at the MirageOS retreat would return whatever RRSIG records it had cached - which in some cases was only the RRSIG for the DS record, and later for many more records if you ran dig +dnssec A my.dnssec.domain. Finally, systemd-resolved outright disallows RRSIG queries because they make little sense.

    ↩︎︎