BIND DoH Update

Status of DNS-over-HTTPS support in BIND 9 as of March, 2021

The latest development release of BIND 9 contains a significant number of improvements to DNS-over-HTTP (DoH). The most noticeable one is the initial support for DoH in the dig utility. It is something that was lacking in the previous release, so we are completing this missing piece. Now dig can be officially added to the Hall of Fame of DoH diagnostic tools.

dig logo using the outline of a shovel for the letter d

Although this is the first release to include this support, it is complete enough to test real-world DoH deployments. It is safe to say that if a DoH deployment does not work with dig, some other clients might have troubles using the service as well. It is particularly good at detecting Application-Layer Protocol Negotiation (ALPN) configuration errors, which might be a non-obvious aspect of DoH deployment for some of our users. We have also tested that it works as expected with many well-known public DNS resolvers supporting DoH.

All HTTP methods required by RFC8484 are supported (GET and POST) for both encrypted and unencrypted connections, with POST being used by default. Here is an example of dig usage for querying the A record for isc.org via the DoH server doh.example.com using the default DoH endpoint location (/dns-query):

$ dig +https @doh.example.com isc.org A

; <<>> DiG 9.17.10 <<>> +https @doh.example.com isc.org A
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56070
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: e40f41fc38f3768e01000000604a20425472ceb9ec62ced0 (good)
;; QUESTION SECTION:
;isc.org.			IN	A

;; ANSWER SECTION:
isc.org.		60	IN	A	149.20.1.66

;; Query time: 306 msec
;; SERVER: 1.2.3.4#443(doh.example.com) (HTTPS)
;; WHEN: Thu Mar 11 15:50:58 EET 2021
;; MSG SIZE rcvd: 80

Dig supports the following methods for querying a DoH-enabled DNS server:

  • +https, +https-post - send a query using the HTTP POST method via an encrypted connection;
  • +https-get - send a query using the HTTP GET method via an encrypted connection;
  • +http-plain, +http-plain-post - send a query using the HTTP POST method via an unencrypted connection;
  • +http-plain-get - send a query using the HTTP GET method via an unencrypted connection.

In the case when a non-default endpoint location should be used (normally /dns-query), one can be specified after the method preceded by the equal sign (e.g. +https=/alternative-location).

The unencrypted modes are supposed to be used for cases when TLS offloading is planned. In these cases, unencrypted HTTP/2 queries are sent without any HTTP protocol version negotiation. As far as we are aware, BIND is the only open source DNS server that supports this feature.

For additional information, you may want to consult the relevant manual pages.

Although the addition of DoH support to dig is the most noticeable change to BIND’s DoH functionality, the server-side code has received a stream of important changes and stability improvements as well. One of the more noticeable ones from the end-user’s perspective is BIND’s ability to return meaningful HTTP status codes in case of errors.

The following HTTP status codes are returned by BIND:

  • 200 OK - the query was received and processed by BIND so that it could return an answer, even if it is a negative one (e.g. SERVFAIL);
  • 400 Bad Request - this signifies that the request contains some consistency errors (e.g. an unexpected header for the given request type, Content-Length equals 0 in the case of POST request etc);
  • 404 Not Found - the wrong endpoint location was specified in the request;
  • 413 Payload Too Large - the size of the payload in POST-request was too large;
  • 414 URI Too Long - this means that there was too much data in the :path pseudo-header in the case of GET-request (which usually means that there was too much Base64URL encoded data in the request);
  • 415 Unsupported Media Type - this means that either the client sent a request of any other media type than application/dns-message, or the client has not specified that it supports this media type;
  • 501 Not Implemented - this means that the type of the HTTP request is anything but POST or GET;
  • 500 Internal Server Error - the generic error code that is returned in any other cases. It usually signifies some low-level problem (e.g. validated Base64URL data from the GET request cannot be decoded).

Here we followed Unbound’s lead and roughly used the same status codes in similar situations (https://blog.nlnetlabs.nl/dns-over-https-in-unbound/). We have to note, though, that in some cases, BIND just resets an HTTP stream if the request is too large or looks malicious, without returning any error codes.

Also, it is now possible to write a shorter configuration file for BIND if all you want is to serve DoH with default settings using a default as an HTTP endpoint name in listen-on statements:

Private key and certificate pair for TLS

tls local-tls {
    key-file "/path/to/priv_key.pem";
    cert-file "/path/to/cert_chain.pem";
};

options {
    listen-on port 53 {any;};
    listen-on-v6 port 53 {any;};
    allow-recursion {any;};
    
    # example for DoH using default configuration
    # listening on all IPv4 addresses.
    # port number can be omitted
    listen-on port 443 tls local-tls http default {any;};

    # the same for IPv6
    listen-on-v6 port 443 tls local-tls http default {any;};
};

You can compare the example above to the similar example from the previous post. We expect most users to use the default configuration for DoH unless they have some very specific needs.

Ephemeral certificates (for testing purposes only)

An additional feature might be handy for testing purposes (although it does not directly relate to DoH). Analogous to specifying the default HTTP endpoint in listen-on statements, one could specify ephemeral as a TLS certificate-key pair. In this case, BIND generates a TLS certificate and key at runtime, saving a bit of the hassle with doing so by hand. In this case, we can make the configuration example above even shorter:

options {
	listen-on port 53 {any;};
	listen-on-v6 port 53 {any;};
	allow-recursion {any;};

	listen-on port 443 tls ephemeral http default {any;};
	listen-on-v6 port 443 tls ephemeral http default {any;};
};

It is worth mentioning that these ephemeral certificates cannot work in real-world deployments, because clients would fail to validate them.

Although BIND with DoH support was first released just a month ago, a lot has happened in this direction since then. DoH support is still an experimental feature, but we ship a much more mature version with this release. However, there are many things to improve and bugs to fix. Hence, we continue working hard to make it possible for our users to deploy this feature in the future, and make it easier to provide a viable alternative to existing centralised services and contribute to the diversity of the Internet infrastructure.

Recent Posts

What's New from ISC