|
|
# BIND9 DoH/DoT design
|
|
|
This document describes the design of the DoT and DoH implementation for BIND9. This will be developed in the 9.17 development branch, and backported to 9.16 (with some exceptions). Unfortunately external Gitlab users cannot comment directly on wiki pages, but comments are welcome here: https://gitlab.isc.org/isc-projects/bind9/-/issues/1144/
|
|
|
|
|
|
## netmgr
|
|
|
BIND 9.16 introduced the new framework for processing incoming requests - netmgr. Previously, the code responsible for processing incoming packets and e.g. reading from sockets and accepting new TCP connections was deeply intertwined - which made it complex, error-prone and made it very hard to add new transports to the code. The idea behind netmgr is to separate the transport layer from the packet processing layer completely.
|
|
|
|
|
|
The code currently supports Do53 for both UDP and TCP - and from the packet processing code perspective there's one single transport-agnostic function that gets a buffer with whole DNS packet (with the 2-byte length stripped for TCP). The DoT and DoH code will also be based on that principle - the transport layer processing will be kept in netmgr, while the query processing code will just receive a buffer with a binary packet.
|
|
|
|
|
|
The netmgr is layered in design - the `tcpdns` module which processes incoming TCP packets uses the netmgr itself, and it can use any type of streaming socket the netmgr supports - TCP for now, TLS for DoT.
|
|
|
|
|
|
## External libraries
|
|
|
The implementation will use two external libraries - OpenSSL for encryption and [NGHTTP2](https://www.nghttp2.org) for http/2. OpenSSL was chosen because it's already used extensively in BIND9 code (and using two crypto libraries simultaneously doesn't make any sense), [NGHTTP2](https://www.nghttp2.org) was chosen as the most popular and well-maintained implementation of http/2 protocol - and DoH mandates http/2 usage.
|
|
|
|
|
|
## TLS layer
|
|
|
The TLS layer will be added as another streaming socket type to netmgr - along with currently implemented TCP. The only difference will be in new connect - `isc_nm_connecttls()`, and listen - `isc_nm_listentls()` functions which will accept TLS context as one of their parameters. Additional generic functions will be added to allow the client code to e.g. get information about connections' TLS parameters. The TLS layer will be using OpenSSL library, using its BIO mechanism to provide IO over netmgr stream sockets.
|
|
|
|
|
|
### DoT server
|
|
|
As it was stated above, the `tcpdns` module uses netmgr itself to communicate over any streaming socket supported by netmgr. That makes adding TLS support quite trivial - the `isc_nm_listentcpdns()` function will accept additional TLS context parameter which, if not `null`, will make the function call `isc_nm_listentls()` instead of `isc_nm_listentcp()` - the rest will be unchanged as it uses generic stream socket functions.
|
|
|
|
|
|
### DoT client
|
|
|
DoT client will be built into dig/delv - it'll be using netmgr `isc_nm_connecttls()` function and then use the acquired socket as any other stream socket. The +dot option will tell dig to use DoT and set the default port to 853.
|
|
|
|
|
|
## http/2
|
|
|
The http/2 layer will be built on top of any streaming socket supported by the netmgr - although the HTTP2 standard itself does not mandate TLS usage, in practice all clients support it and some don't support HTTP2 over an unencrypted connection at all.
|
|
|
Internally the server will be based on nghttp2 library, externally it will be based on URI-callback model - the client (DoH server, statistics channel server) will launch a listener and then add callbacks to specific URIs, keeping the HTTP processing itself separate.
|
|
|
|
|
|
### Statistics channel
|
|
|
BIND9 has a very limited http/1 server built in - it's used to provide statistics channel in JSON and XML formats. With a proper http/2 server, built-in statistics channel will be served with it too
|
|
|
|
|
|
This feature will not be backported to 9.16.
|
|
|
|
|
|
### DoH server
|
|
|
DoH server will be using netmgr http/2 on one side, and the libns client library - specifically, `ns_client_request()` function, on the other - when an http request is received it will parse the incoming packet to a binary buffer, pass it to request processing function and, when the response is ready, pass it on to http server to be sent to the requesting client.
|
|
|
|
|
|
DISCUSS:
|
|
|
- when BIND 9 is compiled with JSON-C library, the DoH server in BIND 9 should be able to also serve `application/dns-json` payload.
|
|
|
|
|
|
### DoH client
|
|
|
DoH client will be built into dig/delv, using netmgr http2 layer (nghttp2 library provides both http2 client and server). DoH usage will be enabled by the '@<server_addr>' option - e.g. `dig isc.org @https://public-dns.isc.org/query`
|
|
|
|
|
|
## Configuration options
|
|
|
DoT and DoH will have to extend BIND9 configuration syntax. Since it's virtually impossible to change the option syntax while keeping backward compatibility the proposed design might change after consulting the community.
|
|
|
|
|
|
### TLS
|
|
|
Since TLS will be used by various services, it'd be convenient to introduce a single configuration option describing TLS parameters - most notably, key and certificate file. The proposed syntax for the option is:
|
|
|
```
|
|
|
tls-config <string> {
|
|
|
key-file <quoted-string>;
|
|
|
cert-file <quoted-string>;
|
|
|
};
|
|
|
```
|
|
|
To make deployment simpler, a generic `default` tls-config with autogenerated certificate might be provided.
|
|
|
|
|
|
DISCUSSION:
|
|
|
- the autogenerated certificate will be emphemeral or saved in a secure place in workdir? (@ondrej)
|
|
|
- should it support ACME protocol (LE) in future? (@ondrej)
|
|
|
- this is also underspecified, there needs to be more global TLS options (using nginx option names) (@ondrej):
|
|
|
* ssl_protocols (1.2 and 1.3, I would prevent anything less)
|
|
|
* ssl_dhparam
|
|
|
* ssl_ciphers (and ecdh ciphers) (ssl_prefer_server_ciphers could be always on?)
|
|
|
* ssl_session configuration (ssl_session_timeout, ssl_session_cache, ssl_session_tickets)
|
|
|
* ssl_stapling and ssl_stapling_verify
|
|
|
|
|
|
### DoT
|
|
|
Configuring listening for TLS connections extends the current listen-on and listen-on-v6 syntax:
|
|
|
```
|
|
|
listen-on [ port <integer> ] [ tls-config <string> ] { <address_match_element>; ... };
|
|
|
```
|
|
|
|
|
|
### DoH
|
|
|
Configuring DoH is more complex, as e.g. multiple views can use the same address, but different endpoints identified by URIs.
|
|
|
|
|
|
A HTTP/2 server is configured by the following options:
|
|
|
```
|
|
|
http-server <string> [ port <integer> ] [ tls-config <string> ] { <address_match_element>; ... };
|
|
|
```
|
|
|
A DoH endpoint for a server is configure with:
|
|
|
```
|
|
|
doh-endpoint <quoted-string> [server <string> ]
|
|
|
```
|
|
|
|
|
|
DISCUSS:
|
|
|
- I would recommend matching the `http-server`/`server` strings, e.g.: `doh-endpoint <quoted-string> [http-server <string> ]` (@ondrej)
|
|
|
- Is it `doh-endpoint` or `http(2)-endpoint`? (@ondrej)
|
|
|
|
|
|
### Example
|
|
|
```
|
|
|
tls-config my_config {
|
|
|
key-file "key.pem";
|
|
|
cert-file "cert.pem";
|
|
|
}
|
|
|
listen-on port 853 tls-config my_config { any; };
|
|
|
http-server my_server port 443 tls-config my_config { any; };
|
|
|
doh-endpoint "/dns-query" server my_server;
|
|
|
```
|
|
|
|
|
|
DISCUSS:
|
|
|
- And example with views would be useful. (@ondrej)
|
|
|
- Example with IPv6 would be useful. (@ondrej)
|
|
|
- I am convinced that we should redesign `listen-on` to be IP version agnostic (and adjust other options v4 vs v6 accordingly) in BIND 9.17+, in BIND 9.16 we need both `listen-on` and `listen-on-v6` (@ondrej)
|
|
|
|
|
|
## Statistics
|
|
|
Additional 'dot' and 'doh' performance counters will be added, similar to the ones for TCP. It's important to note, that since DoT and DoH use TCP as its underlying transport, e.g. DoT connections will be also counted as TCP connections.
|
|
|
|
|
|
## Testing
|
|
|
|
|
|
### Conformance
|
|
|
Conformance testing will be performed using existing tools that support DoT and DoH - such as kdig. Internally, system tests (most likely based on the current 'tcp' test) will be created.
|
|
|
|
|
|
DISCUSS:
|
|
|
- for system tests, the new pytest framework should be used - [requests](https://requests.readthedocs.io/en/master/) + [dnspython](http://www.dnspython.org/) could be used to glue the DoH testing client, and [hyper-h2](https://python-hyper.org/projects/h2/en/stable/) and [dnspython](http://www.dnspython.org/) could be used to glue the DoH testing server.
|
|
|
|
|
|
### Performance
|
|
|
The DoT performance will be tested using `flamethrower` - a DNS performance testing tool with DoT support.
|
|
|
The DoH performance will be tested using `JMeter` - an HTTP performance tool.
|
|
|
|
|
|
DISCUSS:
|
|
|
- what about [bulldohzer](https://help.commons.host/bulldohzer/) for DoH performance testing? |
|
|
\ No newline at end of file |