Notice: Undefined offset: 1 in /usr/local/src/wordpress/wp-content/themes/montezuma/includes/parse_php.php on line 79

HowTo: Prevent DNS Cache Poisoning

~~   Forward   ~~

There has been a long history of attacks on the domain name system, ranging from brute-force DoS attacks to targeted attacks requiring specialized software.   A ne’er-do-well could send a few packets, which result in many packets to the target, an effect called ‘amplification’.   In July 2008 a new DNS cache-poisoning attack was unveiled that is especially dangerous because it doesn’t require substantial bandwidth or CPU nor does it require complex techniques.

With ‘cache poisoning’ an attacker inserts a fake address record into a Domain Name Server.   If the DNS accepts the false record, the cache is poisoned and further requests for that domain are sent to the attacker’s server.   The fake entry is cached by the DNS for as long as the ‘time to live’ (TTL), usually a couple of hours.   So you might think you’re going to your bank or to pay a bill, but you’re handing over your login info to the attacker.

And child caches of that DNS are also poisoned through ‘zone transfers’, when they request an update.   So even a lesser-experienced hacker can cause much trouble, snagging passwords and other valuable information.

So how can a user protect their web access?   By setting up dnscrypt, with DNSSEC, a new security protocol which not only signs, but encrypts all DNS transactions, and by using only a highly secure DNS authority with it. ( and friends)   Also we will multithread this process with 4 instances doing queries in parallel, to speed things up.   While we’re at it we’ll set up ‘unbound’, which is a DNS caching daemon;   this will cache all DNS requests, so that there is no need to reach out to the internet for repeated requests.   I’ve gone to great lengths to explain this all as clearly as possible, and you won’t find this information anywhere else.

~~   Installing   ~~

This HowTo is Debian-centric.

# apt-get install unbound lsof libtool autogen automake gawk command-not-found
# cd /usr/local/src

tarGet the latest libsodium and dnscrypt, both .bz2 and .sig .   Dearchive both to where they belong (under POSIX), /usr/local/src.
(# tar -jxpvf {filename})
# gpg –keyserver –recv-keys 1CDEA439
# gpg *.sig

Make sure the signatures check.   If not, you either have a bad download, or a counterfeit file.

Start with libsodium, as it’s a dependency of dnscrypt:
# ./
# ./configure
# make
# make install
# ldconfig

Make sure there are no errors at any step.
Then do the same with dnscrypt.   You now have the executable:   /usr/local/sbin/dnscrypt-proxy

Now edit the unbound config file:
# nano /etc/unbound/unbound.conf
And make it similar to this:

include: "/etc/unbound/unbound.conf.d/*.conf"



# Set to number of cores in CPU
	num-threads: 8

# Uncomment to get more logging.
#	verbosity: 5

	do-ip6: no
	logfile: /var/log/unbound.log

# Listen on eth0 and answer queries from the local subnet.
	access-control: allow
	access-control: allow

	do-not-query-localhost: no

# -Upstream- resolver is DNSCrypt
	name: "."


– Replace all the red numbers with the IP of the listening interface on your machine.
– If you will only be running and using unbound on your local machine, comment out (#) the lines with 192.168…
– Notice the line

include: "/etc/unbound/unbound.conf.d/*.conf"

This causes Unbound to engage the file root-auto-trust-anchor-file.conf which calls in the key needed for DNSSEC.
– The forward-addr: entries are to route queries to multiple threads of dnscrypt, so we can work them in parallel.   Network and resolver delays are what we’re overcoming around here.   2 threads is probably great but I like 4 better, and if multiple resolvers go down we still get service.
– Save the file.

Now, I’m assuming you’ve converted your Debian system from sysv to the systemd init system, as Debian is moving to this.   I keep all my custom .service files (where they’re supposed to be under the POSIX standard) in /usr/local/lib/system/systemd, so make that directory if it’s not there.   I say the native SysV unbound start script is inferior, so let’s make our own, much better one.
# nano /usr/local/lib/systemd/system/unbound.service
(Be careful of the line-wraps)

Description=Unbound recursive Domain Name Server
After=network.service openvpn.service

ExecStartPre=/usr/sbin/unbound-checkconf /etc/unbound/unbound.conf
ExecStartPre=/usr/sbin/unbound-anchor -a /var/lib/unbound/root.key
ExecStartPre=/bin/chown unbound:unbound /var/lib/unbound/root.key
ExecStart=/usr/sbin/unbound -d


# Security
InaccessibleDirectories=/boot /home /media /mnt /opt /root /sbin /srv /sys
ReadOnlyDirectories=/bin /etc /lib /lib64 /usr
DeviceAllow=/dev/null rw


# mv /etc/init.d/unbound /etc/init.d/unbound.oem
# rm /etc/rc?.d/*unbound
# touch /var/log/unbound.log
# chown unbound:unbound /var/log/unbound.log

dnscrypt does not come with a .service file as it was compiled from source, so we have to make one.
# nano /usr/local/lib/systemd/system/dnscrypt-Holland.service .

Description=dnscrypt encrypting DNS proxy - Holland


# For debugging run on the command-line as root and add --loglevel=1024

# Holland - (dnssec, no logs)
ExecStart=/usr/local/sbin/dnscrypt-proxy --local-address= --user=unbound --logfile=/var/log/dnscrypt-Holland.log


# Security
InaccessibleDirectories=/boot /home /media /mnt /opt /root /sbin /srv /sys
ReadOnlyDirectories=/bin /etc /lib /lib64 /usr
DeviceAllow=/dev/null rw


– Here we have set dnscrypt to be fed by unbound with –local-address=.   (Unbound will listen on 53/udp to and 192.168.?.?. for local DNS queries)   This provides cached name service for the whole LAN.
– If you don’t use Shorewall, replace this with the name of your firewall service.
– I use only resolvers which do DNSSEC, and do not log. (OpenDNS does not yet support DNSSEC, lol)   We will make four of these dnssec-*.service files, each pointing to a different resolver.   In this case we set Holland.   Here’s a list of the latest resolvers.
– Save Holland and copy it to the following files, and make those files’ settings as follows:

dnssec-Holland.service 40 -Holland
dnssec-Denmark.service 41 -Denmark
dnssec-Sydney.service 42 -Sydney cloudns-syd
dnsssec-Canberra.service 43 -Canberra cloudns-can

Why not use systemd templates?   Because they can only pass one variable and we need at least two.   And a variable file is just not worth it for four .services.
– We are setting this up as a rotary, so if a resolver goes down temporarily, it will automatically fall to the next resolver.
– It’s important to note that most dnscrypt howtos tell you to put at the end of the dnscrypt command, –daemonize.   Well this is wrong here because we are using systemd.   –daemonize spins off the process to be its own independent little sewing machine, but in our case systemd will be tending and monitoring it so must retain control.   If dnscrypt fails, it will be automatically restarted by systemd.   But if –daemonize is used, systemd will find that it loses control of the process when it spins off, so it repeatedly stops and restarts it, like an insane rollercoaster.   So set your .service files as above.
– The Security section is not mandatory, but I recommend it.   SysV sure can’t do this stuff.
# touch /var/log/dnscrypt-Holland.log
# touch /var/log/dnscrypt-Denmark.log
# touch /var/log/dnscrypt-Sydney.log
# touch /var/log/dnscrypt-Canberra.log
# chown unbound:unbound /var/log/dnscrypt*

As Debian isn’t able to effectively check when the network is up   (der), we have to roll-our-own.
# nano /usr/local/bin/netcheck


# Try until is accessible
until curl -s; do sleep 1; done

#if curl -s; then echo 'Tor!'; else echo 'no Tor :('; fi

# chmod +x /usr/local/bin/netcheck

It’s important to understand that dnscrypt will not send DNS queries out port 53/udp, as would normally be the case.   It sends them out 443/udp, so that port must be open outgoing in your firewall, or else you won’t have name service.   In fact it would be good to block 53 outgoing since you don’t need it anymore, in case some rootkit wants to use it for communication.

Nice thing we’re going to forge here is dnscrypt running multithreaded.   Most websites these days call other sites for various functions, like G**gleAPIs, Gravitar,,, so they can make sure and track you real good :j, and running dnscrypt multithreaded muchly speeds up loading.   Our main delays are with the network and remote resolver, so we invoke dnscrypt in multiple, independent incantations so it can answer queries in parallel.   We’ve set unbound multithreaded as well locally, in case there is ever CPU or memory contention with it.

~~   Enabling and Checking   ~~

Time to enable our services:
# systemctl daemon-reload
# systemctl enable unbound

ln -s ‘/usr/local/lib/systemd/system/unbound.service’ ‘/etc/systemd/system/’
# systemctl restart unbound.service

We should now have unbound running on this machine, ready to chain to dnscrypt, so let’s check it:
# lsof -i -n -P |grep unbou
unbound 4279 unbound 3u IPv4 24531 0t0 UDP
unbound 4279 unbound 4u IPv4 24532 0t0 TCP (LISTEN)
unbound 4279 unbound 5u IPv4 24533 0t0 UDP
unbound 4279 unbound 6u IPv4 24534 0t0 TCP (LISTEN)

Correct.   unbound is listening on 53/udp (the normal DNS port) on both the localhost, and eth0 to provide name service for the LAN.   And as a bonus it’s listening on 53/tcp in case we want that, although TCP is not necessary or desirable for something like DNS as it is slower, but this is fine because all internet apps use 53/udp.   unbound is listening for DNS requests, and will pass them along to dnscrypt.

# systemctl enable dnscrypt-Holland.service
ln -s ‘/usr/local/lib/systemd/system/dnscrypt-Holland.service’ ‘/etc/systemd/system/’
# systemctl enable dnscrypt-Denmark.service

# systemctl enable dnscrypt-Sydney.service

# systemctl enable dnscrypt-Canberra.service

# systemctl start dnscrypt-Holland.service
# systemctl start dnscrypt-Denmark.service
# systemctl start dnscrypt-Sydney.service
# systemctl start dnscrypt-Canberra.service

# lsof -i -n -P |grep dnscry
dnscrypt-Holland- 3225 unbound 8u IPv4 17200 0t0 UDP
dnscrypt-Holland- 3225 unbound 10u IPv4 17202 0t0 TCP (LISTEN)
dnscrypt-Denmark- 3226 unbound 8u IPv4 17204 0t0 UDP
dnscrypt-Denmark- 3226 unbound 10u IPv4 17206 0t0 TCP (LISTEN)
… etc…

Perfect!   All 4 of our dnscrypt threads are listening on ports 40-43, which are fed by unbound, and will forward those requests to the remote DNS servers.   So the chain is:
Browser –> unbound –> dnscrypt –> DNSSEC server.   All daemons are running as the unprivileged user unbound.

yeserrSurf over to, turn on Javascript, and ‘Start test‘.   If you’re using the TOR Browser it will always fail, as nameservice is through TOR in that case, but with regular browsers it should give you Mr. YesErr here.   No one seems to know why TOR doesn’t use DNSSEC, but it is a wide-open security hole.   I’ve logged a bug, but thusfar am ignored, lol.

Now for the acid test:
# dig com. any +dnssec

; <<>> DiG 9.9.5-4-Debian <<>> com. any +dnssec
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15126
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 21, AUTHORITY: 0, ADDITIONAL: 1

; EDNS: version: 0, flags: do; udp: 4096
;com. IN ANY

com. 900 IN SOA 1408921259 1800 900 604800 86400

com. 74547 IN DNSKEY 256 3 8 AQPbokupKUJ5LLAtDEs6R3nDOHxF2jQEFtJEFTiDcfbsZia4fg3EK9Wv D9ZIr+7t2n1ddqRGHnTTInHTjduaKFPqm2iKaDHdrc6095o1mzqojnd1 bTtI45XNu61QmT5IU4VPT7HDUSby+53gLAsjLPyNsNEMp7Cc52RVxCHD no9efw==
com. 74547 IN DNSKEY 257 3 8 AQPDzldNmMvZFX4NcNJ0uEnKDg7tmv/F3MyQR0lpBmVcNcsIszxNFxsB fKNW9JYCYqpik8366LE7VbIcNRzfp2h9OO8HRl+H+E08zauK8k7evWEm u/6od+2boggPoiEfGNyvNPaSI7FOIroDsnw/taggzHRX1Z7SOiOiPWPN IwSUyWOZ79VmcQ1GLkC6NlYvG3HwYmynQv6oFwGv/KELSw7ZSdrbTQ0H XvZbqMUI7BaMskmvgm1G7oKZ1YiF7O9ioVNc0+7ASbqmZN7Z98EGU/Qh 2K/BgUe8Hs0XVcdPKrtyYnoQHd2ynKPcMMlTEih2/2HDHjRPJ2aywIpK Nnv4oPo/
com. 74547 IN RRSIG DNSKEY

;; Query time: 223 msec
;; WHEN: Sun Aug 24 16:01:21 PDT 2014
;; MSG SIZE rcvd: 1528

Far out.   Here we see that there were no errors in this query, and that flag ad is set, which means this query was answered with the Authenticated Data bit set, indicating that DNSSEC validation was successful.   And we see the two keys that were used in this transaction.

~~   Finalization   ~~

– Edit /etc/resolv.conf
– Comment (#) out any nameserver already there, and make it like this:

options edns0


– Save the file.
– Of course on other machines in your LAN, set nameserver to the IP of the server running unbound and dnscrypt.
– ‘options edns0‘ tells it to use larger buffers, for better performance.

Are you using DHCP or NetworkManager, or some other automatic network service?   If so, it thinks it owns /etc/resolv.conf and reverses any changes you make, without permission.   But you must have resolv.conf set to your unbound resolver.   So to prevent NetworkMangler’s meddling we set resolv.conf to ‘immutable’.
# chattr +i /etc/resolv.conf

Now all internet requests for name service on your machine are going through DNSSEC to a trusted server, encrypted, and responses are signed and encrypted.   Your web browser makes a DNS request to port 53, which is picked up locally by unbound;   if unbound has seen that request before, it instantly serves the answer from its cache to your browser.   If not it wraps it in DNSSEC and passes the query to dnscrypt, which ships it to the trusted name server out port 443/udp.   When it gets the answer back in from 443/udp it passes it to unbound, which passes it to your browser.

~~   Tune it Up   ~~

This is optional, but recommended if you’re in the US as these four servers are so far away.   There can be a wide divergence in performance of DNSSEC resolvers;   for example, Japan these days is averaging over 2 seconds to resolve a name.   So I ran a test series on the four resolvers I’ve chosen — dig five times in a row, each time flushing the unbound cache so I always get the initial lookup time — testing each resolver this way.   From Seattle, WA here are my results, in milliseconds:

Holland Denmark Sydney Canberra
1038 1090 1349 3063
685 945 971 1022
878 932 973 1014
829 945 964 993
832 911 1002 790

Almost a second per lookup looks kind of bad, but these are all initial lookups.   Most lookups you do day-to-day are repeats which will come from the local unbound cache.   These cached lookups are very fast, from 0 – 1 millisecond!

To run these tests yourself, you’ll want to first specify the resolver you want to test.   Assuming you have everything set up as above, edit /etc/unbound/unbound.conf and toward the bottom comment out forward-dir: for the three resolvers you will not test, leaving the one you will.   Save, and:
# systemctl restart unbound
# dig |grep time

;; Query time: 669 msec

Now that domain name is cached by unbound, so we have to flush the cache in order to get a good test.   As unbound’s cache is only in memory we just have to restart it:
# systemctl restart unbound
# dig |grep time

;; Query time: 842 msec

Run this 5 times so you get a good read on how the resolver is performing.   Then in unbound.conf change your resolver to test another one.   And so on.

Once you have your table of times, it will be clear which are the worst and best resolvers from your location.   unbound chooses resolvers in order, so you’ll want the one at port 40 to be fastest, port 41 next-fastest, and so on. Set the port in your dnscrypt-*.service files.   Then enable all resolvers in unbound.conf, systemctl daemon-reload, and restart unbound and all dnscrypts.   You are now optimised.

~~   Troubleshooting   ~~

You’re not getting nameservice, huh.   First question is whether your firewall is configured right.   Close 53 outbound and open 443/udp outbound.   Check your logs for firewall errors.

Then are both services actually running?   Check those as described above with # lsof -i -n -P |grep unbound .   Make sure that unbound is on port 53 and dnscrypt is on ports in the 40’s.   Verify that unbound.conf is correct, and that unbound.service and dnscrypt-*.service are right.

If those are not the problem, the question becomes whether it us unbound, or dnscrypt at fault.   Each has logfiles in /var/log which may help with the problem.   If there’s little to go on there, there’s a technique called “The Old Air Force Half-Split Method“, or at least that’s how I learned it.   For any system that’s malfunctioning, split it in half and see if the problem is on the left, or right.   Then split that again.   And again, until you narrow down the problem.

First we’re going to make sure that unbound is working.   On your firewall, open port 53/udp outgoing.   Then edit /etc/unbound/unbound.conf and comment out (#):

#	name: "."
#	forward-addr:
#	forward-addr:
#	forward-addr:
#	forward-addr:

# systemctl restart unbound
# ping

PING ( 56(84) bytes of data.
64 bytes from ( icmp_seq=1 ttl=42 time=280 ms
64 bytes from ( icmp_seq=2 ttl=42 time=90.3 ms

Oh.   What does this mean?

We have name service when using unbound only, so the problem must be with dnscrypt.

The best way to test dnscrypt is to run it on the command-line with –loglevel=1024.   This will give lots of diagnostic information which will hopefully indicate the problem.
# systemctl stop dnscrypt-Holland
# /usr/local/sbin/dnscrypt-proxy –loglevel=1024 –local-address= –user=unbound –

[NOTICE] Starting dnscrypt-proxy 1.4.0
[INFO] Initializing libsodium for optimal performance
[INFO] Generating a new key pair
[INFO] Done
[INFO] Server certificate #808464433 received
[INFO] This certificate looks valid
[INFO] Chosen certificate #808464433 is valid from [2013-12-27] to [2014-12-27]
[INFO] Server key fingerprint is 6231:4AFE:4AA3:7E6F:9B8C:DAA6:6F6E:E8A5:F84B:10A8:6DB1:C5CB:D264:77CA:7F03:0D5C
[NOTICE] Proxying from to

In this case it’s running well, but you will see differences if yours is at fault.

When you find and fix the problem, put unbound.conf right again and close port 53 on your firewall.   And then it’s Party Time!!

,'after' => '

') )