I recently heard about the DNSCrypt system which encrypts DNS queries (which are always sent in the clear) with upstream DNS servers. While DNSSEC helps to ensure that DNS responses are valid and have not been tampered with in transit, responses are still sent in the clear and anyone can see the requests. DNSCrypt uses TLS to encrypt the entire request and respond (akin to difference between HTTP and HTTPS). DNSCrypt focuses mainly on a piece of client software that is installed on your machine(s) and DNS queries are redirected to the client which then encrypts and sends queries to an upstream DNS provider (in my case I went with CISCO’s OpenDNS). The problem with this is that every machine requires a client. This is all but impractical for all but the smallest networks. With over 100 devices on my network I needed something more robust. I wanted to install it on my gateway router, so that all machines even my IoT devices which don’t have access to my internal DNS still have encrypted DNS to OpenDNS. Unfortunately the only documentation I could fine (here) was almost 3 years old, and required downloading a pre-built binary. Instead I wanted a up-to-date build of DNSCrypt and Libsodium (the encryption library that DNSCrypt uses).
I therefore went about building my own version for use on ZeroShell. Below are the steps I used to build the latest version of DNSCrypt (1.7.0) and Libsodium (1.0.11) as the writing of this article.
A couple of things to note up front
- I am by no means an Linux expert. Whilst I am very comfortable using Linux I am not that well versed in building packages from source code, so if there are things that more knowledge users see that could be done better, by all means drop a comment.
- The build I used is with the 32bit version of CentOS. I initially tried the 64 bit version (as I am running the 64 bit version of the ZeroShell kernel) but it failed miserably with the executables not being runnable by ZeroShell. If anyone knows how to overcome this please let me know.
Ok on to building the software:
- Install CentOS 7 32bit. The software can be downloaded here. I used the CentOS-7-i386-Everything-1511.iso. I use VMWare Fusion, but any VM software would work. I won’t go into how to install CentOS in a VM, if you need help Google is your friend. I will mention that I installed it with the install option of a development workstation, this gives you a GUI (which is not needed if you are comfortable with the command line) but most importantly it installs all of the development tools needed to build software under linux
- Once CentOS is installed be sure to make sure it is up-to-date by running sudo apt-get update && sudo apt-get upgrade
- Next download the latest version of Libsodium from https://download.libsodium.org/libsodium/releases/. (Make sure you grab the *nix version at this writing its libsodium-1.0.11.tar.gz not the one with msvc which is the windows version). Decompress the file and open up your terminal and cd into your unzipped folder.
- Next run configure
./configure --enable-static --prefix=/Database/dnscrypt/libsodium
- Next run make (This will create a new folder at /Database which will have both Libsodium and DNSCrypt)
make && sudo make install
- Next create the usr_local_lib.conf file used by Libsodium.
sudo touch /etc/ld.so.conf.d/usr_local_lib.conf
- Next add the libsodium library to the conf file.
sudo echo /Database/dnscrypt/libsodium/lib > /etc/ld.so.conf.d/usr_local_lib.conf
- Run the ldconfig application to configure libsodium.
sudo ldconfig
- Create symbolic links to where dnscrypt expects the libsodium libraries to be.
sudo ln -s /Database/dnscrypt/libsodium/lib/libsodium.so.18 /usr/lib/libsodium.so.18
sudo ln -s /Database/dnscrypt/libsodium/lib/libsodium.so /usr/lib/libsodium.so
- Next download the latest version of DNSCrypt at https://download.dnscrypt.org/dnscrypt-proxy. Decompress the file and open up your terminal and cd into your unzipped folder.
- Copy the libsodium header files to the src folder in dnscrypt.
cp /Database/dnscrypt/libsodium/include/sodium.h src/proxy/sodium.h
cp -R /Database/dnscrypt/libsodium/include/sodium src/proxy/sodium
- Run configure & make
./configure --libdir=/Database/dnscrypt/libsodium/lib --enable-static --prefix=/Database/dnscrypt && make
- Finally install libsodium.
sudo make install
- Next download the source code for CDE (Code, Data & Environment). This application packages up a linux binary with all necessary dependencies to make the software easily portable between different distributions of Linux. More info available at http://www.pgbovine.net/cde.html.
cd ~
git clone git://github.com/pgbovine/CDE.git
cd CDE
make && sudo make install
- Next run CDE to create the self contained linux binary.
sudo cde -o ~/dnscrypt /Database/dnscrypt/sbin/dnscrypt-proxy --resolver-name=cisco
- Press CTRL + Z to kill the process
- Now compress the folder with the software.
tar -zcvf ~/dnscrypt.tar ~/dnscrypt
- Copy the dnscrypt.tar folder located at the root of you home folder to the /Database folder on your zeroshell install. I’ll be honest this wasn’t exactly clear on how to get a file from my VM onto Zeroshell. Normally I would just scp from the VM to zeroshell. The problem with this is that when you ssh/scp into zeroshell, you don’t immediately get the shell prompt. Instead you get zeroshell’s startup menu which requires you to type in ‘S’ and then re-authenticate before you get the prompt. So several options to try are:
- Copy the file to a web server and then use wget on zeroshell to download the file
- scp from the Zeroshell to your computer and copy the file this way (only works if your host computer is running *nix) This is what I used, I secure copied from the VM to my Mac. And then from zeroshell secure copied from my Mac to zeroshell.
- Now decompress the dsncrypt.tar folder.
tar -jxvf dnscrypt.tar
- Create a startup script to run dnscrypt when zeroshell boots up.
sudo nano /Database/startdnscrypt.sh
- Type in the following code (Basically what is happening is you are telling Zeroshell to forward all DNS queries it receives to itself on port 1053 (–local-address-127.0.01:1053) which DNSCrypt is listening for requests on. DNSCrypt will then forward the query to OpenDNS (-R cisco) over port 443:
#!/bin/bash
sed -i -e 's/forwarders { 0.0.0.0; };/forwarders { 127.0.0.1 port 1053; };/g' /Database/var/register/system/dns/named.conf
killall -HUP named
/Database/dnscrypt/cde-exec /Database/dnscrypt/sbin/dnscrypt-proxy -R cisco --daemonize --local-address=127.0.0.1:1053 &
- Save the file. And then make it executable.
sudo chmod 755 /Database/startdnscrypt.sh
- Now log on to the ZeroShell GUI via your web browser
- Click on DNS under Network on the left
- Click on Forwarders. If there are any forwarders listed, select them and remove them.
- Under domain type in ANY and Server type in 0.0.0.0 and then click Add
- Close the window
- Click on Setup on the left and then Scripts/Cron.
- Make sure Post Boot is selected.
- At the bottom of the script type in
/Database/startdnscrypt.sh
- Click Test if you get no errors then everything has gone correctly and now DNSCrypt is running. Click Save to save the changes to your Post Boot script.
- To verify DNSCrypt is running, back in the terminal window on your ZeroShell type in
dig txt debug.opendns.com
- In the output you should see a line that says “dnscrypt enabled”
- You can also text from your client by typing in
dig txt @IP_OF_ZEROSHELL debug.opendns.com
It’s important to remember that you will only see the dnscrypt enabled if you are querying from the server that has DNSCrypt installed. In my case I have two intermediate DNS servers that handle internal DNS hosts, and a pihole installation that does ad blocking at the network level via DNS for my entire domain. Those DNS queries are not encrypted as they are all internal to my network. Any requests now that leave my network are always encrypted. Finally depending on your network configuration you may need to adjust DNS options for clients to make sure that the zeroshell is somewhere in the chain of DNS resolvers. In my network for example for trusted internal computers DHCP issues a DNS address for my internal BIND9 server. That server points to the pihole for DNS resolution that BIND9 does not know about. That server running DNSMASQ points to zeroshell now for DNS resolution which is then encrypted and sent to OpenDNS. For less trusted systems (IoT) they only point to the ZeroShell DNS for queries.