Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

DoT and mTLS

DNSY serves DNS over TLS (RFC 7858) on every address in dot.listen (conventionally :853). An empty listen disables the listener.

[dot]
listen = ["0.0.0.0:853"]
cert = "/etc/dnsy/dot.pem"   # certificate chain, PEM, leaf first
key  = "/etc/dnsy/dot.key"   # private key, PEM (PKCS#8, PKCS#1 or SEC1)

cert and key are required when listen is set; the server refuses to start if they cannot be read or do not match.

TLS

  • TLS 1.2 and 1.3 with rustls’ default cipher suites (ring provider); older versions are not offered.
  • ALPN dot is advertised. Clients that send no ALPN extension are still served.
  • Framing, pipelining, the idle timeout (limits.tcp_idle_ms), the connection cap (limits.max_tcp_conns) and shutdown draining are the same as for plain TCP. The TLS handshake also has to finish within the idle timeout. A plain TCP client talking to the DoT port fails the handshake and is closed.
  • Responses are padded to a multiple of 468 octets (RFC 8467) when the query carried an EDNS Padding option (RFC 7830).
  • Queries reach the engine with transport dot.

Certificate hot reload

The certificate and key are re-read when either file changes (the parent directories are watched, so atomic renames and Kubernetes secret symlink swaps work) and on SIGHUP. New handshakes use the new certificate; established connections are not dropped. If the new files are unreadable or the key does not match the certificate, the previous certificate stays in use and a warning is logged (without key material).

mTLS

[dot]
mtls = "required"                  # off | optional | required
client_ca = "/etc/dnsy/clients-ca.pem"   # PEM bundle of CAs that issue client certificates
  • off: no client certificate is requested.
  • optional: clients may connect without a certificate; a presented certificate must be valid.
  • required: a handshake without a valid certificate is refused (with TLS 1.3 the client sees the failure on its first read, not in connect).

Validation is rustls’ WebPkiClientVerifier: the chain must lead to client_ca, and the certificate must be within its validity period. client_ca must be set whenever mtls is not off.

Revocation (CRL)

Set dot.client_crl to a PEM file of CRLs (it needs dot.listen and dot.mtls other than off). Revoked certificates are refused. The file is read at startup (a missing one is a startup error) and re-read together with the CA bundle. MtlsVerifier::reload (or spawn_reload(interval)) re-reads the CA bundle and CRL file; if the new files are unreadable, empty or contain no CRL, the previous state is kept and a warning is logged. With a CRL configured, a certificate whose issuer is not covered by a CRL is refused.

Fingerprint allowlist

When an Allowlist is attached, a certificate that passes chain validation must also be on the list, otherwise the handshake fails. Entries are stored in the client_certs table (migration 0008) and managed through ClientCertService: SHA-256 of the DER certificate, a label, an enabled flag and an optional expiry (ids are AUTOINCREMENT since migration 0014, so a deleted entry’s id is never reused). Allowlist::refresh / spawn_refresh load the enabled, unexpired entries; a list with no entries admits no certificate. Disabling, deleting or expiring an entry takes effect for new handshakes at the next refresh.

Resumption and open connections

TLS session resumption is disabled whenever mTLS is on (no session cache, no tickets), because a resumed session would skip certificate verification. Every handshake re-verifies the chain, the CRL and the allowlist. A connection that stays open is re-checked on its next query after the CA, CRL or allowlist changed, and at least every 30 seconds regardless, so a certificate that simply expires (leaf notAfter, or the allowlist entry’s expires_at) stops working on a long-lived connection; if the certificate is no longer permitted the connection is closed. Enable it with DotConfig::with_mtls.

Client identity

For a connection with a client certificate every request carries the principal ClientCert { sha256, subject }: the fingerprint and a short CN=... SAN=... string, available to ACLs and the query log. Raw certificates are never logged.