DNS over HTTPS with cloudflared
In last weeks post I went over using Unbound to encrypt DNS traffic. The main downside to this was uncached DNS queries had a fairly high latency. In this post I'm going to look at an alternative approach using cloudflared.
The cloudflared daemon is fairly straightforward to install, on
CentOS it can be installed with
yum install https://bin.equinox.io/c/VdrWdbjqyF/cloudflared-stable-linux-amd64.rpm
Note: the RPM download link above was taken from CloudFlare's download page.
Once the cloudflared package is installed, you should be able to run
$ cloudflared --version cloudflared version 2018.5.6 (built 2018-05-23-1637 UTC)
cloudflared is primarily used to connect to Argo Tunnel
Servers, however it can also be used to proxy DNS traffic
over HTTPS. This is done with the
$ cloudflared proxy-dns WARN Cannot determine default configuration path. No file [config.yml config.yaml] in [~/.cloudflared ~/.cloudflare-warp ~/cloudflare-warp /usr/local/etc/cloudflared /etc/cloudflared] INFO Adding DNS upstream url="https://188.8.131.52/dns-query" INFO Adding DNS upstream url="https://184.108.40.206/dns-query" INFO Starting DNS over HTTPS proxy server addr="dns://localhost:53" INFO Starting metrics server addr="127.0.0.1:37593"
There are also several options that can be used to control the DNS proxy. For example if you wanted to disable auto updates, and use Google as the upstream DNS you could use the following command:
cloudflared --no-autoupdate proxy-dns \ --upstream https://dns.google.com/experimental?ct
Note: at the time of writing DNS over HTTPS is still a draft standard (draft-ietf-doh-over-https-07); and shouldn't be confused with Google's DNS-over-HTTPS API.
cloudflared is running, as well as providing a DNS endpoint, it also
provides metrics over HTTP:
$ curl 127.0.0.1:34197/metrics |grep cpu_seconds # HELP process_cpu_seconds_total Total user and system CPU time spent in seconds. # TYPE process_cpu_seconds_total counter process_cpu_seconds_total 0.02
Unfortunately the cloudflared package only includes the binary; therefore it will not start at boot. This can be fixed by creating a custom unit file with the following contents:
[Unit] Description=CloudFlare DNS proxy Documentation=https://developers.cloudflare.com/220.127.116.11/dns-over-https/cloudflared-proxy/ After=network.target [Service] Type=simple ExecStart=/usr/local/bin/cloudflared --no-autoupdate proxy-dns ProtectSystem=strict [Install] WantedBy=multi-user.target
Save the unit file as
then run the following commands to enable and start the service:
systemctl daemon-reload systemctl enable cloudflared-proxy-dns.service systemctl start cloudflared-proxy-dns.service
Like Unbound, cloudflared has to initially establish a TLS connection which introduces noticeable latency:
$ time host example.com 127.0.0.1 Using domain server: Name: 127.0.0.1 Address: 127.0.0.1#53 Aliases: example.com has address 18.104.22.168 example.com has IPv6 address 2606:2800:220:1:248:1893:25c8:1946 real 0m0.546s user 0m0.004s sys 0m0.002s
However unlike Unbound, the TLS connection is kept open, consequently subsequent queries are significantly faster because the TLS connection is reused:
$ time host example.org 127.0.0.1 Using domain server: Name: 127.0.0.1 Address: 127.0.0.1#53 Aliases: example.org has address 22.214.171.124 example.org has IPv6 address 2606:2800:220:1:248:1893:25c8:1946 real 0m0.282s user 0m0.002s sys 0m0.005s