DNS over TLS
  • Updated on 01 Nov 2018
  • 3 minutes to read
  • Contributors
  • Print
  • Share
  • Dark

DNS over TLS

  • Print
  • Share
  • Dark

RFC 7858 specifies DNS over TLS (Transport Layer Security). This article explains how to provide a DNS over TLS service using BIND 9 and stunnelThe setup of a privacy aggregator is at the end.

BIND 9 configuration: nothing special, but if you want to limit external insecure access to the service you can play with listen-on clause address and port, acl, or even system firewall as BIND 9 provides no per-transport protocol access control.

stunnel setup for the opportunistic privacy profile:

  • Create a X.509 public key certificate, for instance by:
openssl genrsa -out dns.key 1024

openssl req -new -key dns.key -out dns.crt -x509

This creates a self-signed certificate, enough for clients performing no authentication.

  • Create a stunnel configuration dnstls.conf:

accept = 853

connect =

cert = dns.crt

key = dns.key

The service_name should be dns according to documentation. The DNS over TLS well-known port is 853; stunnel will accept any TLS connection on this port and forward content in TCP to (localhost) on port 53(dns).

  • Launch stunnel in daemon mode using the configuration file:
stunnel dnstls.conf

stunnel setup for the the out-of-band key-pinned privacy profile:

  • You should use a real X.509 CA but for experiments you can create a CA certificate by:
openssl genrsa -out ca.key 1024

openssl req -new -key ca.key -out ca.crt -x509 -extensions v3_ca
  • Create a X.509 public key certificate in a X.509 Certificate Authority, for instance the homemade CA: 
openssl genrsa -out dns.key 1024

openssl req -new -key dns.key -out dns.req

openssl x509 -req -in dns.req -out dns.crt -CA ca.crt -CAkey ca.key -CAcreateserial
  • Add in stunnel configuration:
CAfile = ca.crt

This makes stunnel add the CA certificate to the chain during TLS handshake (as it is supposed to do).

  • Launch stunnel in daemon mode

How to test the service using getdns (https://getdnsapi.net).

  • Install (or configure and compile) getdns with the getdns_query tool you can find in src/test of the distribution.

  • If you'd like to authenticate the server, the CA must be known. The simplest way to do it is:

$ export SSL_CERT_FILE=.../ca.crt

% setenv SSL_CERT_FILE .../ca.crt

If you have a shell or a c-shell filling the ... by the path where the OpenSSL library can find the CA certificate.

openssl rsa -in dns.key -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64

or from the certificate:

openssl x509 -in dns.crt -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
  • A typical call could be:
getdns_query -s foo.example.org a @ -l L

-l L ask for TLS transport (vs. U for UDP or T for TCP)

  • or with key-pinning:
getdns_query -s foo.example.org a @ -l L -K 'pin-sha256="KAGwR1fXzY4JJtBP1yYoAisc+4yNomT6VrFPwkMi5qE="' -m

-K specifies a public key pin, -m requires authentication (vs -n for no authentication).

BIND 9 setup for a privacy aggregator uses for instance:

options {


    forwarders { port 1053; };

    forward only;


server {

    tcp-only yes;



forwarders makes all queries to be forwarded to the designated service on another port, forward only disables fallback to standard resolution, the tcp-only clause in the server entry enforces the use of TCP transport (note this feature was added in version 9.11).

stunnel setup for a privacy aggregator is in client mode with for instance:


client = yes

accept = localhost:1053

connect = <server>:853

To test the privacy aggregator setup: <client_hosts> --- *:53 <named> localhost:1053 <stunnel> ---- *:853 <unbound> an unbound configuration could be:




    ssl-port: 853

    ssl-service-key: dns.key

    ssl-service-pen: dns.crt

    do-udp: no
Was this article helpful?