As of release 239 systemd-resolved now supports opportunistic DNS-over-TLS - see the resolved.conf man page. The release notes say:
systemd-resolved now supports DNS-over-TLS. It's still turned off by default, use DNSOverTLS=opportunistic to turn it on in resolved.conf. We intend to make this the default as soon as couple of additional techniques for optimizing the initial latency caused by establishing a TLS/TCP connection are implemented.
However see this ISOC article on some issues with this implementation.
Recommended: See the DNS Privacy Daemon - Stubby web page for how to use Stubby as a local DNS Privacy stub resolver on your desktop or laptop!
Unbound can be run as a local caching forwarder, configured to use SSL upstream, however it cannot yet send several of the privacy related options (padding, ECS privacy) etc. The 1.7.1 release of Unbound supports authentication of upstream recursive resolvers using an authentication domain name (i.e. PKIX authentication) if a certificate bundle is configured. The 1.13.1 release can re-use upstream connections. An example minimal config is given below.
server: directory: "/etc/unbound" username: unbound chroot: "/etc/unbound" # logfile: "/etc/unbound/unbound.log" #uncomment to use logfile. pidfile: "/etc/unbound/unbound.pid" # verbosity: 1 # uncomment and increase to get more logging. # listen on local host, port 53 interface: 127.0.0.1@53 interface: 0::1@53 prefetch: yes hide-identity: yes hide-version: yes do-not-query-localhost: no # specifiy a path to a local certificate bundle to authenticate connections tls-cert-bundle: "/etc/ssl/cert.pem" forward-zone: name: "." forward-addr: 184.108.40.206@853#cloudflare-dns.com forward-tls-upstream: yes
Some user combine Unbound (as a caching proxy with other features such as DNS Blacklisting) and Stubby (as fully featured TLS forwarder).
Matthew Vance has developed a docker solution that sets this configuration up.
Or, if you want to set this up yourself, an example config for this is:
server: use-syslog: yes username: "unbound" directory: "/etc/unbound" trust-anchor-file: trusted-key.key root-hints: "/etc/unbound/root.hints" do-not-query-localhost: no forward-zone: name: "." forward-addr: 127.0.0.1@8053 forward-addr: ::1@8053
resolution_type: GETDNS_RESOLUTION_STUB dns_transport_list: - GETDNS_TRANSPORT_TLS tls_authentication: GETDNS_AUTHENTICATION_REQUIRED tls_query_padding_blocksize: 256 edns_client_subnet_private : 1 idle_timeout: 10000 listen_addresses: - 127.0.0.1@8053 - 0::1@8053 round_robin_upstreams: 1 upstream_recursive_servers: ...
As of the 2.0.0 release knot resolver can also forward queries over TLS!
Bind does not support TLS natively but can be configured to run behind a local TLS proxy such as stunnel.
Lars de Bruin has kindly created a docker image which uses BIND as a caching local resolver with Stubby as a TLS forwarder.
|Quad 9 has an App: Quad9 Connect|
|iOS||Work in underway on a Stubby iOS app, however it is currently blocked by an implementation restriction.|
|Cloudflare has an app call 220.127.116.11 - it does DoH by default but will also do DoT but only uses 18.104.22.168|
Tenta is a browser for Android that encrypts DNS queries using DNS-over-TLS
If you want a DNS Privacy enabled command line tool or a library then choose from one of the following:
Query: To query this with drill use: (the IP address is used here simply to stop the server name resolution falling back to TCP because your local resolver doesn't support DNS-over-TLS).
drill -t @<serverIP> <query name> (to see TCP query)
drill -l -p1021 @<serverIP> <query name> (to see TLS query)
drill -C @<serverIP> <query name> (to see STARTTLS query)
drill -C -D @<serverIP> <query name> (to do a DNSSEC lookup using STARTTLS)
Chrome has a full DoH implementation but the configuration for it is not exposed. However if you want to try it out use something like the following example for macOS:
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --enable-features="dns-over-https<DoHTrial" --force-fieldtrials="DoHTrial/Group1" --force-fieldtrial-params="DoHTrial.Group1:server/https%3A%2F%2Fcloudflare-dns%2Ecom%2Fdns-query/method/POST"