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.
Reference
https://developers.google.com/speed/public-dns/docs/dns-over-tls
https://askubuntu.com/questions/1092498/dns-over-tls-with-systemd-resolved/1197682
https://fedoramagazine.org/use-dns-over-tls/
Fedora specific (DNS over TLS via systemd-resolved)