Problem statement

What is a DNS?

The Domain Name System (DNS) is a hierarchical and decentralized naming system for computers, services, or other resources connected to the Internet or a private network. It associates various information with domain names assigned to each of the participating entities.

The problem with DNS is primarily privacy.

From the dnsprivacy.org site I’ve extracted some from the many issues:

  • Whilst the data in the DNS is public, individual transactions made by an end user should not be public.
  • However DNS queries are sent in clear text (using UDP or TCP) which means passive eavesdroppers can observe all the DNS lookups performed.
  • Some ISPs log DNS queries at the resolver and share this information with third-parties in ways not known or obvious to end users.

Is there any solution

There are multiple solutions:

  • DNS-over-TLS (DoT)
  • DNS-over-HTTP (DoH)
  • DNS-over-DTLS
  • DNSCrypt
  • DNS-over-HTTPS (proxied)
  • DNS-over-QUIC
  • DNSCurve

In this post I’m going to describe how to implement DNS-over-TLS (DoT) that can be shared across all your private LAN, for further information on how the various solutions compare see here.

DNS-over-TLS (DoT)

The use of Transport Layer Security (TLS) provides privacy for DNS.

Encryption provided by TLS eliminates opportunities for eavesdropping and on-path tampering with DNS queries in the network.

DoT implementation: Stubby

Stubby is an application that acts as a local DNS Privacy stub resolver (using DNS-over-TLS). Stubby encrypts DNS queries sent from a client machine (desktop or laptop) to a DNS Privacy resolver increasing end user privacy.

Raspbian installation

Install build dependencies:

sudo apt install -y git automake build-essential libssl-dev libtool m4 autoconf libyaml-dev

Clone and configure getdns project:

git clone https://github.com/getdnsapi/getdns.git
cd getdns
git submodule update --init
libtoolize -ci
autoreconf -fi
mkdir -v build && cd build
../configure --prefix=/usr/local --without-libidn --without-libidn2 --enable-stub-only --with-stubby

Build and install:

make
sudo make install

Install runtime dependencies:

sudo apt install -y libev4 libevent-core-2.0.5 libuv1 libidn11 dns-root-data libunbound2
cd ~
wget http://pyyaml.org/download/libyaml/yaml-0.2.2.tar.gz
tar xvf yaml-0.2.2.tar.gz
cd yaml-0.2.2
./configure
make
sudo make install

Edit stubby configuration:

vi /usr/local/etc/stubby/stubby.yml

My configuration uses cloudflare dns as first choice and quad9 as fallback:

resolution_type: GETDNS_RESOLUTION_STUB
# Enable DoT
dns_transport_list:
  - GETDNS_TRANSPORT_TLS
# Strict mode TLS only
tls_authentication: GETDNS_AUTHENTICATION_REQUIRED
tls_query_padding_blocksize: 128
edns_client_subnet_private : 1
# Set to 0 to treat the upstreams below as an ordered list and use a single
# upstream until it becomes unavailable, then use the next one.
round_robin_upstreams: 0
idle_timeout: 10000
# Set the listen addresses for the stubby DAEMON. IPv4 only.
# Note: 127.0.2.2 is a loopback valid address but any other in
# the 127.0.0.0/8 range (except .1 that collides with pihole's one) can be used.
listen_addresses:
  - 127.0.2.2
# Require DNSSEC validation.
dnssec: GETDNS_EXTENSION_TRUE
appdata_dir: "/var/cache/stubby"
upstream_recursive_servers:
  - address_data: 1.1.1.1
    tls_auth_name: "cloudflare-dns.com"
  - address_data: 1.0.0.1
    tls_auth_name: "cloudflare-dns.com"
  - address_data: 9.9.9.9
    tls_auth_name: "dns.quad9.net"
  - address_data: 9.9.9.10
    tls_auth_name: "dns.quad9.net"

Install it:

sudo /usr/bin/install -Dm644 /usr/local/etc/stubby/stubby.yml /etc/stubby.yml

Create a systemd service:

sudo vi /lib/systemd/system/stubby.service

With content:

[Unit]
Description=Stubby DNS resolver
Wants=network-online.target
After=network-online.target

[Service]
ExecStart=/usr/local/bin/stubby -C /etc/stubby.yml
Restart=on-abort

[Install]
WantedBy=multi-user.target

Enable and start it

sudo systemctl daemon-reload
sudo systemctl enable stubby
sudo systemctl start stubby

Pi-hole

Combining Stubby with Pi-hole we can obtain a perfect match of privacy and performance.

Installing it is quick and easy, just follow the documentation site.

Configure Stubby as the only upstream DNS server.

Benchmark

Using dnsperftest script results are pretty good:

bash ./dnstest.sh | sort -k 22 -n
                  test1   test2   ... test10  Average
cloudflare        24 ms   26 ms   ... 27 ms     26.00
pi-hole-stubby    73 ms   6 ms    ... 16 ms     32.90
google            39 ms   23 ms   ... 27 ms     35.70
cleanbrowsing     34 ms   31 ms   ... 37 ms     36.90
neustar           37 ms   33 ms   ... 37 ms     38.00
level3            46 ms   30 ms   ... 41 ms     39.00
norton            41 ms   33 ms   ... 42 ms     39.40
quad9             50 ms   45 ms   ... 35 ms     43.90
adguard           48 ms   49 ms   ... 46 ms     50.60
opendns           20 ms   26 ms   ... 22 ms     56.50
yandex            72 ms   120 ms  ... 62 ms     99.20
freenom           80 ms   168 ms  ... 148 ms    111.80
comodo            1000 ms 1000 ms ... 1000 ms   815.00