This article describes how to install and configure dnscrypt-proxy to use DNSCrypt and DNS-over-HTTPS (DoH) with DNSSEC.

The article is intended for the following software versions:

OS: Linux with systemd

Package: dnscrypt-proxy v2

Tested on: Debian 10

Installation and configuration steps should be mostly applicable to distros using systemd and dnscrypt-proxy v2 .

What is DNSCrypt and DNS-over-HTTPS?

While browsing on the web, people almost always use the domain name instead of the IP address of the requested resource. However, the domain name must first be resolved to a corresponding IP address by a DNS resolver. In most cases, the DNS resolver is assigned by the Internet Service Provider (ISP). Moreover, even if the requested website uses HTTPS, DNS queries use a different protocol and they are sent in plain-text by default.

These problems are addressed by both DNSCrypt and DNS-over-HTTPS (DoH). To start with, DNSCrypt is the name of the protocol which provides encryption and authentication between the client and the DNS resolver. It uses elliptic curve cryptography. Like DNSCrypt, DNS-over-HTTPS also encrypts the data but using HTTPS protocol, as the name suggests. By using either one of them, people can significantly lower the probability of request and/or tampering, thus preventing man-in-the-middle attacks [1,2].

Apart from DNSCrypt and DoH, DNS data can be further secured by the use of DNS Security Extensions (DNSSEC). It provides DNS data authentication, data integrity and authenticated denial of existence. As a result, attacks such as DNS cache poisoning can be mitigated [3].

Considering the benefits, encrypting DNS queries is an important part of Linux hardening. In order to use DNSCrypt, DoH and DNSSEC, we are going to use dnscrypt-proxy as the client, which supports both protocols.

Install and configure dnscrypt-proxy

dnscrypt-proxy exists both in Debian and Ubuntu repositories. Thus, you can install it via: sudo apt-get update sudo apt-get install dnscrypt-proxy

exists both in Debian and Ubuntu repositories. Thus, you can install it via: Check the systemd socket file by: cat /lib/systemd/system/dnscrypt-proxy.socket You should see the listening IP and the port, similar to: [Socket] ListenStream=127.0.2.1:53 ListenDatagram=127.0.2.1:53 NoDelay=true DeferAcceptSec=1 In this case it is listening on 127.0.2.1 and port 53.

socket file by: Make sure that nothing else is listening on the same address:port pair from the previous step by: sudo ss -lp 'sport = :domain' Depending on the distro, systemd-resolved might be using the same address:port pair. If that is the case, it can be disabled via the following: sudo systemctl stop systemd-resolved.service sudo systemctl disable systemd-resolved.service

Edit dnscrypt-proxy configuration in /etc/dnscrypt-proxy/dnscrypt-proxy.toml to include: dnscrypt_servers = true doh_servers = true require_dnssec = true This will enable both DNSCrypt and DoH supporting servers. In addition, it requires the DNSSEC support. Optionally, if you would like to use only the no-log and no-filter (parental filters, ad blocking etc.) resolvers, you can add: require_nolog = true require_nofilter = true If you have a system where IPv6 is disabled and/or your ISP does not provide IPv6 connectivity, you might want to disable it also in dnscrypt-proxy . This would result in immediate refused responses, therefore you might realize faster connections. block_ipv6 = true ipv6_servers = false

to include: Backup the existing resolv.conf file: sudo cp /etc/resolv.conf /etc/resolv.conf.backup

file: Remove the existing resolv.conf : sudo rm -f /etc/resolv.conf

: Create and edit /etc/resolv.conf to have: nameserver 127.0.2.1 # the listening address in dnscrypt-proxy.socket file options edns0 Here, nameserver 127.0.2.1 tells that DNS queries are sent to the specified address, at which dnscrypt-proxy.socket is listening. If your socket file has a different address, you should configure resolv.conf accordingly. Also, edns0 is required to be able to use DNSSEC.

to have: Prevent network manager from changing the resolv.conf : sudo chattr +i /etc/resolv.conf At least in Debian and Ubuntu, the Network manager configures the nameserver automatically when a connection is established. Therefore, if you do not set an immutable bit on resolv.conf , it will be overridden.

: Start and enable the dnscrypt-proxy via systemd : sudo systemctl start dnscrypt-proxy.socket sudo systemctl enable dnscrypt-proxy.socket sudo systemctl start dnscrypt-proxy.service sudo systemctl enable dnscrypt-proxy.service

via : Test if EDNS0 is active by: drill rs.dns-oarc.net TXT Look for “EDNS: version: 0” entry in the output.

Test if the dnscrypt-proxy selected resolvers are really using DNSSEC validation: DNSSEC Resolver Test.

selected resolvers are really using DNSSEC validation: DNSSEC Resolver Test. As the last thing, you need to check if there is a DNS leak. This can be done via DNSleaktest. You should only see the resolvers specified in the following list: DNSCrypt Resolvers. By default, this is the list used by dnscrypt-proxy when selecting the best resolver, constrained by your requirements in the /etc/dnscrypt-proxy/dnscrypt-proxy.toml configuration file.

Installation and configuration sources: [4,5,6]

Using dnscrypt-proxy with captive portals

If you have applied the steps until this section, you will realize that captive portal logins, such as those in hotels, cafes and airports would not work. The reason is that usually, the hotspot needs to first redirect the client to an internal authentication page before allowing the access to the web. However, it cannot do this, because the network manager cannot override the nameserver in resolv.conf with the one from the router.

Thus, you need to temporarily remove the modifications made to resolv.conf and restart the network manager, then after logging in into the captive portal, you can safely re-enable DNSCrypt/DoH. Below is a bash script to achieve this goal:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #!/bin/bash # Exit script as soon as a command fails. set -o errexit RESOLV_CONF = /etc/resolv.conf DNSCRYPT_RESOLV = /etc/resolv.conf.dnscryptBackup sudo cp $RESOLV_CONF $DNSCRYPT_RESOLV sudo chattr -i $RESOLV_CONF sudo rm -f $RESOLV_CONF echo "Restarting the NetworkManager" sudo systemctl restart NetworkManager echo "Wait for the connection" echo "Then, login to the captive portal" while true do read -p "Did you login?(Y/N) " answer case $answer in [ yY] * ) sudo rm -f $RESOLV_CONF sudo cp $DNSCRYPT_RESOLV $RESOLV_CONF sudo rm -f $DNSCRYPT_RESOLV sudo chattr +i $RESOLV_CONF echo "Final nameservers:" cat $RESOLV_CONF echo "Restarting dnscrypt-proxy..." sudo systemctl restart dnscrypt-proxy echo "Done" break ;; [ nN] * ) exit ;; * ) echo "Enter Y or N, please." ;; esac done

References