DNS Privacy

DNS over TLS Solution

Home Network DNS over TLS Solution

Asus RT-AC86U with Asuswrt-Merlin (384.11+ and newer offer DoT support) as Main (edge) router + Internet Gateway

NOTE: Asuswrt-Merlin uses stubby to implement DoT.

The DNS query traffic flow is illustrated below

plain text

|

|

desktop / laptop <=== UDP 53 ===> stub resolver <=== TLS handshake port 853 ===> 1.1.1.1:853

| |

| |

loopback addr SNI: cloudflare-dns.com

systemd-resolved or 1.1.1.1 (any in SAN)

stubby/knot resolver

Get the TLS certificate used by DoT server

openssl s_client -connect 1.1.1.1:853 </dev/null 2>&1 | openssl x509 -noout -text

...

# snippet

X509v3 Subject Alternative Name:

DNS:cloudflare-dns.com, DNS:*.cloudflare-dns.com, DNS:one.one.one.one, IP Address:1.1.1.1, IP Address:1.0.0.1, IP Address:162.159.132.53, IP Address:2606:4700:4700:0:0:0:0:1111, IP Address:2606:4700:4700:0:0:0:0:1001, IP Address:2606:4700:4700:0:0:0:0:64, IP Address:2606:4700:4700:0:0:0:0:6400, IP Address:162.159.36.1, IP Address:162.159.46.1

...

All devices (running Linux x86_64 / ARM, Android, or macOS, iOS, etc.) connected to the core switch + edge router will be configured to use router as DNS nameserver (DO NOT override the configuration on client side, e.g. manually set it to 1.1.1.1 will be using plain UDP over port 53) and subsequently use 1.1.1.1 to do name resolution via DNS-over-TLS.

To cover road warrior use cases, for now the solution is to simply use WireGuard to encrypt all outbound traffic to avoid leaking DNS when (the WireGuard VPN server will be the main attack surface, it's a different topic though).

DNS utilities / Tools

kdig (a part of knot)

    • Fedora / CentOS

    • knot-utils

    • Debian / Ubuntu

    • knot-dnsutils

    • Arch Linux / Manjaro

    • knot

How kdig works with DoT:

kdig -d @1.1.1.1 +tls-ca +tls-hostname=cloudflare-dns.com google.com

root@netbook:~# kdig -d @1.1.1.1 +tls-ca +tls-hostname=cloudflare-dns.com google.com

;; DEBUG: Querying for owner(google.com.), class(1), type(1), server(1.1.1.1), port(853), protocol(TCP)

;; DEBUG: TLS, imported 150 system certificates

;; DEBUG: TLS, received certificate hierarchy:

;; DEBUG: #1, C=US,ST=California,L=San Francisco,O=Cloudflare\, Inc.,CN=cloudflare-dns.com

;; DEBUG: SHA-256 PIN: V6zes8hHBVwUECsHf7uV5xGM7dj3uMXIS9//7qC8+jU=

;; DEBUG: #2, C=US,O=DigiCert Inc,CN=DigiCert ECC Secure Server CA

;; DEBUG: SHA-256 PIN: PZXN3lRAy+8tBKk2Ox6F7jIlnzr2Yzmwqc3JnyfXoCw=

;; DEBUG: TLS, skipping certificate PIN check

;; DEBUG: TLS, The certificate is trusted.

;; TLS session (TLS1.2)-(ECDHE-SECP256R1)-(ECDSA-SHA256)-(AES-256-GCM)

;; ->>HEADER<<- opcode: QUERY; status: NOERROR; id: 64651

;; Flags: qr rd ra; QUERY: 1; ANSWER: 1; AUTHORITY: 0; ADDITIONAL: 1

;; EDNS PSEUDOSECTION:

;; Version: 0; flags: ; UDP size: 1452 B; ext-rcode: NOERROR

;; QUESTION SECTION:

;; google.com. IN A

;; ANSWER SECTION:

google.com. 244 IN A 172.217.167.110

;; Received 55 B

;; Time 2019-12-12 11:41:04 AEDT

;; From 1.1.1.1@853(TCP) in 10.5 ms

Alternatives

    • getdns

    • LDNS (drill)

DNS Privacy (DoT) Clients - local forwarders

    • snot resolver

    • stubby

    • unbound

    • ubuntu/stubby combo

    • dnscrypt-proxy

Linux with systemd flavoured init / systemd-resolved (243+)

Fedora 32 (NAS) / Arch Linux / Ubuntu 20.04 LTS and later

/etc/systemd/resolved.conf

[Resolve]

DNS=1.1.1.1 1.0.0.1 8.8.8.8

# FallbackDNS=1.1.1.1 9.9.9.10 8.8.8.8 2606:4700:4700::1111 2620:fe::10 2001:4860:4860::8888

# Domains=

# LLMNR=yes

# MulticastDNS=yes

# DNSSEC=allow-downgrade

DNSSEC=yes

# DNSOverTLS=opportunistic

DNSOverTLS=yes

# Cache=yes

# DNSStubListener=yes

# ReadEtcHosts=yes

Restart systemd-resolved

systemctl restart systemd-resolved.service

# if not yet enabled

systemctl enable --now systemd-resolved.service

# tail systemd-resolved log

journalctl -u systemd-resolved.service -f

Use 127.0.0.53 as nameserver, the way you like. For example, use stub

# symlink resolved stub file

ln -s /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf

Verify the outbound traffic is going through TLS (port 853) using tcpdump

tcpdump -tttt -nn -i <interface> dst 1.1.1.1 and port 853


Pi-hole ad-blocking and DNS sinkhole (blackhole)

Pi-hole running on Raspbian + nginx + php-fpm backed by the original Raspberry Pi Model B!

Network level ad-blocking and filtering (censor...). The blocking / filtering happen before TCP connections will be established, as DNS queries to blocked sites will fail (never be able to establish TCP connection and then TLS -> HTTP, etc.).

Pi-Hole configuration

plain text (LAN)

|

|

desktop / laptop <=== UDP 53 ===> Pi-Hole (FTLDNS) <=== UDP 53===> Router (DNS over TLS) <=== TLS handshake port 853 ===> 1.1.1.1:853

| |

| |

pihole-FTL SNI: cloudflare-dns.com

based on dnsmasq or 1.1.1.1 (any in SAN)

router as upstream

IMPORTANT: Configure conditional forwarding for router (so that DNS queries appear to come from clients, instead of router itself).

NOTE: Pi-Hole can be installed on supported Linux distributions (Fedora, Ubuntu, Debian, Raspbian, CentOS) or Dockerized.

https://pi-hole.net/

Reference