Saturday, March 21, 2015

DNSCrypt-Proxy + Unbound + OpenVPN

DNS is akin to 'the weakest link' on the internet. We have evolved from http to https, yet DNS queries are still sent in plain text, for anyone to see, and leaving users open to cache poisoning, man in the middle attacks, and other crappy stuff. Finally, there is a solution! And no, its not dnssec, but rather dnscrypt-proxy.

I've been doing a lot of VPN related stuff lately, and today I figured out how to run dnscrypt-proxy on a vpn server, and route all client dns queries through dnscrypt. It is a wonderful, but irritating program to install. I thought I'd share my configurations here, to help others, but also so that next time I have to do this I will have a reference.

First, install dnscrypt-proxy. If you are running something Debian based on the server, this auto-install script is great. (If you're on another system, or don't trust that code, grab it from the main site.) However, I did have to create the init scripts and configuration files myself. Never fear, the instructions are here.

First, install dnscrypt-proxy and unbound. I used this debian auto-installer I found on github.

git clone https://github.com/simonclausen/dnscrypt-autoinstall

chmod +x dnscrypt-autoinstall.sh
./dnscrypt-autoinstall.sh && sudo apt-get install unbound



Edit: If the compiler is complaining about a syntax error....

checking whether to enable maintainer-specific portions of Makefiles... no
./configure: line 3264: syntax error near unexpected token `SYSTEMD,'
./configure: line 3264: `  PKG_CHECK_MODULES(SYSTEMD, libsystemd, have_systemd=yes,'


Than try my dirty hack.

Now let's configure unbound. Unbound will act as our dns-cache, and also our dns server for the
local VPN network.

cd /etc/unbound
vi unbound.conf


Edit your configuration so that unbound is listening on the VPN server IP address, as well as the localhost.

# Unbound configuration file for Debian.
#
# See the unbound.conf(5) man page.
#
# See /usr/share/doc/unbound/examples/unbound.conf for a commented
# reference config file.

server:
    # The following line will configure unbound to perform cryptographic
    # DNSSEC validation using the root trust anchor.
    auto-trust-anchor-file: "/var/lib/unbound/root.key"
server:
   # access-control: 10.8.0.0/24 allow
    logfile: "/var/log/unbound.log"
    log-time-ascii: yes
    module-config: "iterator"
    do-not-query-localhost: no
    interface: 127.0.0.1
    interface: 10.8.0.1
    access-control: 127.0.0.1 allow
    access-control: 10.8.0.1/24 allow
forward-zone:
   name: "."
   forward-addr: 127.0.0.1@40
   forward-first: no

remote-control:
       control-enable: no


Check to make sure that dnscrypt has it's own user:

cat /etc/shadow | grep dnscrypt

 dnscrypt:!:16516:0:99999:7:::

If not, add one:

adduser --system --home /run/dnscrypt --shell /bin/false --group --disabled-password --disabled-login dnscrypt

Next, let's try to start dnscrypt-proxy. You may get a variety of errors, which we will fix. If it's already running, close it. Depending on your installation, you may have a configuration file in

/etc/default/dnscrypt-proxy

If not, (as was the case on my debian server), we will simply create an init script with the desired settings. Dnscrypt is random with it's installs. Try starting it up:

service dnscrypt-proxy start
sudo netstat -taupean | grep dnscrypt


If you see dnscrypt running in the netstat output, great. Now just edit the /etc/default/dnscrypt-proxy config file so that it is listening on a port other than 53, as not to conflict with our caching service, Unbound (port 40 in this example). If you get an error, proceed to the next step:

cd /etc/init.d
vi dnscrypt

And paste in this script:

#! /bin/sh
### BEGIN INIT INFO
# Provides: dnscrypt-proxy
# Required-Start: $local_fs $network
# Required-Stop: $local_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: dnscrypt-proxy
# Description: dnscrypt-proxy secure DNS client
### END INIT INFO
# Author: Simon Clausen <kontakt@simonclausen.dk>
# Edited by Chev Y.
PATH=/usr/sbin:/usr/bin:/sbin:/bin
DAEMON=/usr/local/sbin/dnscrypt-proxy
NAME=dnscrypt-proxy
case "$1" in
start)
echo "Starting $NAME"


#Edit: In most situations, this simple line of code will do the trick:

$DAEMON --daemonize --user=dnscrypt --local-address=127.0.0.1:40 -R opendns



#I had to do this the first time though:

#   /usr/local/sbin/dnscrypt-proxy --local-address=127.0.0.1:40 --edns-payload-size=4096 
# --pidfile=/run/dnscrypt/dnscrypt-proxy.pid --logfile=/var/log/dnscrypt-proxy.log
# --user=dnscrypt -R opendns --daemonize


;;
stop)
echo "Stopping $NAME"
pkill -f $DAEMON
;;
restart)
$0 stop
$0 start
;;
*)
echo "Usage: /etc/init.d/dnscrypt-proxy {start|stop|restart}"
exit 1
;;
esac

###End Init script

Remember, you may already have an init script in that directory. If so, skip that step.

You can choose a different name server to use, after the -R flag. There is a list of them here: https://github.com/jedisct1/dnscrypt-proxy/blob/master/dnscrypt-resolvers.csv

Now update the settings:

 update-rc.d dnscrypt-proxy defaults

Restart Unbound and Start Dnscrypt:

sudo service unbound restart && sudo service dnscrypt start

Update your /etc/resolv.conf file to that it reads

nameserver 127.0.0.1

Set iptables so that the vpn network may access unbound:

iptables -A INPUT -s 10.8.0.0/24 -p tcp -m tcp --dport 53 -j ACCEPT
iptables -A INPUT -s 10.8.0.0/24 -p udp -m udp --dport 53 -j ACCEPT


And finally, edit either your server.conf or ccd/client file(s) so that DNS is served by the VPN server:

push "dhcp-option DNS 10.8.0.1"


Make sure that worked. From a client, run:

dig @10.8.0.1 google.com

And check that the query was answered by the nameserver you selected for dnscrypt to use. Note: if you continue to have trouble starting dnscrypt, check that directory /run/dnscrypt is owned by the user dnscrypt:

ls -la /run/dnscrypt
In some cases user dnscrypt must own this directory or the program won't start.


That's it. Congraduations, your VPN server and all it's client's DNS queries are now fully encrypted! Kiss cache poisoning goodbye.
 

No comments:

Post a Comment