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.
Installing cloudflared
The cloudflared daemon is fairly straightforward to install, on
CentOS it can be installed with yum
:
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
cloudflared version 2018.5.6 (built 2018-05-23-1637 UTC)
Running cloudflared
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 proxy-dns
command:
$ cloudflared proxy-dns
WARN[0000] Cannot determine default configuration path. No file [config.yml config.yaml] in [~/.cloudflared ~/.cloudflare-warp ~/cloudflare-warp /usr/local/etc/cloudflared /etc/cloudflared]
INFO[0000] Adding DNS upstream url="https://1.1.1.1/dns-query"
INFO[0000] Adding DNS upstream url="https://1.0.0.1/dns-query"
INFO[0000] Starting DNS over HTTPS proxy server addr="dns://localhost:53"
INFO[0000] 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.
Daemon metrics
Once 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
Configuring systemd
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/1.1.1.1/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 /etc/systemd/system/cloudflared-proxy-dns.service
, and
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
Query latency
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 93.184.216.34
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 93.184.216.34
example.org has IPv6 address 2606:2800:220:1:248:1893:25c8:1946
real 0m0.282s
user 0m0.002s
sys 0m0.005s