Introduction:
ISP: Comcast
Modem: Motorola SB6141
Router: Ubiquiti EdgeMax Router Lite
EdgeOS System Image: v1.9.7+hotfix.3
WAN Interface: eth0
LAN Interface: eth1 (172.16.0.1)
For this guide, I use the IP address 172.16.0.1
as the one I want dnscrypt-proxy bind to. So far, I have not found a way to configure dnscrypt-proxy to natively bind to only eth1 and eth2.
Installation:
ssh
into your EdgeRouter Lite andsudo
to rootmkdir ~/dnscrypt-proxy && cd ~/dnscrypt-proxy
curl --remote-name https://download.dnscrypt.org/dnscrypt-proxy/binaries/linux/dnscrypt-proxy-mips-linux-musl.tar.gz
curl --remote-name https://download.dnscrypt.org/dnscrypt-proxy/binaries/linux/dnscrypt-proxy-mips-linux-musl.tar.gz.minisig
- TODO: Figure out how to get
minisign
working on the ERL, https://jedisct1.github.io/minisign/ tar xvfz dnscrypt-proxy-mips-linux-musl.tar.gz
cd dnscrypt-proxy
./installer.sh
cd ~ && rm -rf ~/dnscrypt-proxy
Configuration:
First off, run /opt/dnscrypt-proxy/mips-linux-musl/bin/dnscrypt-update-resolvers.sh
to update your local cache of DNSCrypt Resolvers.
Create the dnscrypt-proxy
system user which will run the actual proxy:
useradd --comment 'dnscrypt-proxy system user' --no-create-home --system --user-group --shell /usr/sbin/nologin --home-dir /opt/dnscrypt-proxy dnscrypt-proxy
The following config will start the dnscrypt-proxy on port 153
for us to verify everything works.
/opt/dnscrypt-proxy/dnscrypt-proxy.conf
:
ResolverName random
ResolversList /opt/dnscrypt-proxy/mips-linux-musl/.sw/dnscrypt-proxy/share/dnscrypt-proxy/dnscrypt-resolvers.csv
Daemonize no
PidFile /var/run/dnscrypt-proxy.pid
User dnscrypt-proxy
LocalAddress 172.16.0.1:153
LocalCache on
EphemeralKeys off
MaxActiveRequests 250
EDNSPayloadSize 1252
IgnoreTimestamps no
TCPOnly no
QueryLogFile /var/log/dnscrypt-proxy/queries.log
LogFile /var/log/dnscrypt-proxy/proxy.log
LogLevel 6
# Syslog off
# SyslogPrefix dnscrypt
BlockIPv6 yes
Note that this is going to run dnscrypt-proxy
on port 153
, if you've configured strict firewall rules on your ERL, temporarily add a new rule to allow access to 153
from your test client (or your entire internal network).
chown -R dnscrypt-proxy:dnscrypt-proxy /opt/dnscrypt-proxy/
/opt/dnscrypt-proxy/mips-linux-musl/bin/dnscrypt-proxy /opt/dnscrypt-proxy/dnscrypt-proxy.conf
Now, on a client host that can hit the ERL on port 153, issue the following:
dig techsmix.net @172.16.0.1 -p 153
You should see a completed response:
❯ dig techsmix.net @172.16.0.1 -p 153
; <<>> DiG 9.8.3-P1 <<>> techsmix.net @172.16.0.1 -p 153
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 55928
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1252
;; QUESTION SECTION:
;techsmix.net. IN A
;; ANSWER SECTION:
techsmix.net. 300 IN A 192.241.192.75
;; Query time: 318 msec
;; SERVER: 172.16.0.1#153(172.16.0.1)
;; WHEN: Sun Sep 17 12:19:55 2017
;; MSG SIZE rcvd: 57
And in /var/log/dnscrypt-queries.log
see a line like:
Sun Sep 17 16:36:16 2017 172.16.0.65 techsmix.net A
Now, that the test is working let's reconfigure our ERL to only expose dnscrypt-proxy as the internal DNS server.
Edit /opt/dnscrypt-proxy/dnscrypt-proxy.conf
so that LocalAddress
is 172.16.0.1:53
and Daemonize
is yes
.
At this point, you should see that the ERL has a dnsmasq
process running if you've enabled the DNS service:
root@main-router:~/dnscrypt-proxy# netstat -tulnp | grep 53
tcp 0 0 0.0.0.0:53 0.0.0.0:* LISTEN 1489/dnsmasq
tcp 0 0 172.16.0.1:153 0.0.0.0:* LISTEN 12584/dnscrypt-prox
tcp6 0 0 :::53 :::* LISTEN 1489/dnsmasq
tcp6 0 0 :::49153 :::* LISTEN 1497/upnpd
udp 0 0 0.0.0.0:53 0.0.0.0:* 1489/dnsmasq
udp 0 0 172.16.0.1:153 0.0.0.0:* 12584/dnscrypt-prox
udp6 0 0 :::53 :::* 1489/dnsmasq
Remove all DNS configuration via the ERL's WebUI: https://address.to.erl.here/#Services/DNS
Verify that there's no processes holding port 53
open:
root@main-router:~/dnscrypt-proxy# netstat -tulnp | grep 53
tcp 0 0 172.16.0.1:153 0.0.0.0:* LISTEN 12584/dnscrypt-prox
tcp6 0 0 :::49153 :::* LISTEN 1497/upnpd
udp 0 0 172.16.0.1:153 0.0.0.0:* 12584/dnscrypt-prox
Kill the old test process and start the real one
ps aux | grep dnscrypt && kill $(cat /var/run/dnscrypt-proxy.pid) && /opt/dnscrypt-proxy/mips-linux-musl/bin/dnscrypt-proxy /opt/dnscrypt-proxy/dnscrypt-proxy.conf
And now, verify that dnscrypt-proxy
has taken over port 53
:
root@main-router:~/dnscrypt-proxy# netstat -tulnp | grep 53
tcp 0 0 172.16.0.1:53 0.0.0.0:* LISTEN 13493/dnscrypt-prox
tcp6 0 0 :::49153 :::* LISTEN 1497/upnpd
udp 0 0 172.16.0.1:53 0.0.0.0:* 13493/dnscrypt-prox
Assuming your clients on your network are already using your router for DNS, you should immediatly start seeing the queries in /var/log/dnscrypt-queries.log
. If that's not the case, navigate to https://your.erl.address.here/#Services/DHCP/Server and configure the "DNS 1" option to be your ERL's internal IP (in this example, it would be 172.16.0.1
).
It's reccomended that you add the following cronjob to keep the local list of DNSCrypt servers updated:
0 * * * * /opt/dnscrypt-proxy/mips-linux-musl/bin/dnscrypt-update-resolvers.sh > /dev/null 2>&1
Finally, to ensure that dnscrypt-proxy starts automatically on your ERL, you'll need to create and enable the SysVinit script. I've used please-run
to generate the following init script
/etc/init.d/dnscrypt-proxy
: https://gist.github.com/jaredledvina/f76d72404df3fb5e3fe9ba978755ac7f
Now, you'll want to make sure the new init script works so, let's kill the manually run daemon and start it cleanly with this init script:
kill $(cat /var/run/dnscrypt-proxy.pid)
service dnscrypt-proxy start
Again, you should see the dnscrypt-proxy
service running and listening on the configured interface and port.
Finally, I use chkconfig
to managing the services to run at boot (install it with apt-get install chkconfig
):
root@main-router:~# chkconfig -l dnscrypt-proxy
dnscrypt-proxy 0:off 1:off 2:off 3:off 4:off 5:off 6:off
Enable it to start at boot:
root@main-router:~# chkconfig --add dnscrypt-proxy
dnscrypt-proxy 0:off 1:off 2:on 3:on 4:on 5:on 6:off
Optionally, if you'd like some simple Ad blocking via dnscrypt-proxy perform the following:
cd /opt/dnscrypt-proxy && curl --remote-name https://download.dnscrypt.org/blacklists/domains/mybase.txt'
Add this line to /opt/dnscrypt-proxy/dnscrypt-proxy.conf
:
'BlackList domains:/opt/dnscrypt-proxy/mybase.txt logfile:/var/log/dnscrypt-proxy/blocked.log
Finally, restart dnscrypt-proxy and you should start seeing the deny actions logged to /var/log/dnscrypt-proxy/blocked.log
.
/var/log/dnscrypt-proxy/blocked.log
:
root@main-router:/opt/dnscrypt-proxy# tail /var/log/dnscrypt-blocked.log
Sun Sep 17 19:01:55 2017 172.16.0.65 msec.xp1.ru4.com *ru4.com
4Sun Sep 17 19:01:55 2017 172.16.0.65 msec.xp1.ru4.com *ru4.com
5Sun Sep 17 19:01:55 2017 172.16.0.65 msec.xp1.ru4.com *ru4.com
6Sun Sep 17 19:01:55 2017 172.16.0.65 sync-tm.everesttech.net *everesttech.net
7Sun Sep 17 19:01:55 2017 172.16.0.65 sync-tm.everesttech.net *everesttech.net
8Sun Sep 17 19:01:55 2017 172.16.0.65 aa.agkn.com *agkn.com
9Sun Sep 17 19:01:55 2017 172.16.0.65 ag.innovid.com *innovid.com
10Sun Sep 17 19:01:55 2017 172.16.0.65 ag.innovid.com *innovid.com
You can add a simple cronjob like the following to keep that file always up to date:
0 1 * * * cd /opt/dnscrypt-proxy/ && /usr/bin/curl -s --remote-name https://download.dnscrypt.org/blacklists/domains/mybase.txt > /dev/null 2>&1 && service dnscrypt-proxy restart > /dev/null 2>&1
There you have it! All of your local network DNS queries are automatically proxied securely using DNSCrypt. Enjoy!
Some followups to this article that I will hopefully find time to track down and implement:
- Build ERL
.deb
packages that include a proper SysVinit script and manages all of the install - Configure dnsproxy-crypt to bind to multiple internal only interfaces
- Locking down DNS traffic such that it must use dnscrypt-proxy to leave the internal network
- Deploying something like https://github.com/Phillipmartin/gopassivedns to monitor all DNS traffic for anything that doesn't use dnscrypt-proxy.
- Setup logrotate for the various dnscrypt-proxy log files.
/etc/logrotate.d/dnscrypt-proxy
:
/var/log/dnscrypt-proxy/blocked.log {
daily
missingok
notifempty
compress
copytruncate
size 1M
rotate 2
postrotate
/usr/sbin/service dnscrypt-proxy restart
endscript
}
/var/log/dnscrypt-proxy/proxy.log {
daily
missingok
notifempty
compress
copytruncate
size 1M
rotate 2
postrotate
/usr/sbin/service dnscrypt-proxy restart
endscript
}
/var/log/dnscrypt-proxy/queries.log {
daily
missingok
notifempty
compress
copytruncate
size 1M
rotate 2
postrotate
/usr/sbin/service dnscrypt-proxy restart
endscript
}