How to use dnscrypt-proxy to secure DNS queries in Linux

How to use dnscrypt-proxy to secure DNS queries in Linux

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
    
  • 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.

  • 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
    
  • Backup the existing resolv.conf file:
    sudo cp /etc/resolv.conf /etc/resolv.conf.backup
    
  • 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.

  • 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
    
  • 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.
  • 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

  1. [1]DNSCrypt. Wikipedia. Retrieved from https://en.wikipedia.org/wiki/DNSCrypt
  2. [2]DNS over HTTPS. Wikipedia. Retrieved from https://en.wikipedia.org/wiki/DNS_over_HTTPS
  3. [3]DNSSEC - What is it and why is it important? Internet Corporation for Assigned Names and Numbers (ICANN). Retrieved from https://www.icann.org/resources/pages/dnssec-what-is-it-why-important-2019-03-05-en
  4. [4]dnscrypt-proxy. ArchWiki. Retrieved from https://wiki.archlinux.org/index.php/Dnscrypt-proxy
  5. [5]DNSCrypt. InstallGentoo Wiki. Retrieved from https://wiki.installgentoo.com/index.php/DNSCrypt
  6. [6]Dnscrypt-proxy Wiki. GitHub. Retrieved from https://github.com/DNSCrypt/dnscrypt-proxy/wiki
 •  Edited on Jan 3, 2020
Did you like that article?  You can subscribe to the  RSS feed  or follow  @kumotoko  on Twitter.