Skip to content

Unbound as DNS cache

ronnylov edited this page Jun 26, 2019 · 1 revision

When a user opens a web page in a web browser he/she enters a web address in name form like https://www.youtube.com. To make the connection the web browser have to ask a Domain name Server what IP address to use to connect to this server. This is called DNS lookup. When using VPN this lookup goes through the VPN tunnel (hopefully if you don't have a DNS leak) and connects to the DNS server from the exit node. The Internet Service Provider normally have a DNS server but there are also other public DNS servers on internet. The DNS lookup needs some time, especially if it goes through VPN tunnel to an exit node in other country, then from the exit node to a DNS server that could be in a third country.

It is possible to install a DNS server on the exit node itself that forwards requests and store the answers in a cache memory. This means the second time a VPN user want to connect to the same server the local DNS server read the answer from cache memory instead of ask the remote server. This make the request much faster and the user will get better response. So shortly described the user will feel that wep pages start to load faster. This can make a huge impact on the user experience and make the difference to get rated "fast" instead of "slow". In other words it would give you happier users.

Sometimes the Linux OS installations come with a DNS cashing server installed by default. It could be bind9, dnsmasq or unbound. Could be other options too but these are the ones I have tried and seen. First we take a quick look if we can find one of these services running.

$ systemctl status

We could also try a DNS lookup and see what server address giving the response. If using a local DNS cache the response would come from 127.0.0.1. We install the drill tool by installing ldnsutils on debian:

$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install ldnsutils

Alternatively there is a very similar program named dig which can be installed by dnsutils package. drill is more leightweight as I understand it and have some extra features.

Now let's try to lookup youtube.com

$ drill youtube.com
;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 8565
;; flags: qr rd ra ; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;; youtube.com. IN      A

;; ANSWER SECTION:
youtube.com.    300     IN      A       216.58.204.142

;; AUTHORITY SECTION:

;; ADDITIONAL SECTION:

;; Query time: 34 msec
;; SERVER: 213.186.33.99
;; WHEN: Fri Jun 14 16:26:49 2019
;; MSG SIZE  rcvd: 45

We can see that the lookup time from the server itself was 34 milliseconds (0.034 s). The server that answered have ip address 213.186.33.99 which is not on localhost (it would have been 127.0.0.1 if it was local). The response time is added to the response time over the VPN connection so it makes some extra time. However in this case 34 ms is not much. Let's try it once more.

$ drill youtube.com
;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 63146
;; flags: qr rd ra ; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;; youtube.com. IN      A

;; ANSWER SECTION:
youtube.com.    37      IN      A       216.58.204.142

;; AUTHORITY SECTION:

;; ADDITIONAL SECTION:

;; Query time: 0 msec
;; SERVER: 213.186.33.99
;; WHEN: Fri Jun 14 16:31:12 2019
;; MSG SIZE  rcvd: 45

Wow! 0 ms! In this case it is probably so that there is a DNS server installed on the VPS host operating system or a DNS server at the same data center as this server. So we already got a very good DNS cache by default. But let's say we want to change to some public DNS server like Quad9 because we like the malware protection they offer. On Linux the DNS server is set in the file /etc/resolv.conf so we edit this as usual with nano.

$ sudo nano /etc/resolv.conf

comment out the nameserver line add add your own:

#nameserver 213.186.33.99
nameserver 9.9.9.9

Save and exit nano as usual Ctrl-O, Ctrl-X

NOTE: Sometimes this change does not stick after a reboot. Perhaps resolvconf is installed on the server. In this case we are just demonstrating so it does not matter.

Now try the DNS lookup again and we try some less commonly used address that is less likely to be cached:

$ drill lethean.io
;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 19286
;; flags: qr rd ra ; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;; lethean.io.  IN      A

;; ANSWER SECTION:
lethean.io.     300     IN      A       198.185.159.144
lethean.io.     300     IN      A       198.49.23.144
lethean.io.     300     IN      A       198.185.159.145
lethean.io.     300     IN      A       198.49.23.145

;; AUTHORITY SECTION:

;; ADDITIONAL SECTION:

;; Query time: 102 msec
;; SERVER: 9.9.9.9
;; WHEN: Fri Jun 14 16:44:21 2019
;; MSG SIZE  rcvd: 92

We can see that the responding server is 9.9.9.9 and we got 102 ms response time. Tried it again and got 331 ms. Third time 189 ms and so on. This starts to get noticed by users. If we still want to use this half-slow DNS server we can add our own DNS-cache by installing unbound.

$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install unbound

Now we are going to set up unbound as DNS forwarder, which means it use another DNS-server to forward requests if it can't be found in the DNS cache memory. So we edit the configuration file.

$ sudo nano /etc/unbound/unbound.conf

NOTE: If you have disabled ipv6 as recommended above you should also disable ipv6 in unbound. The following example config disable ipv6 and also set it to use 9.9.9.9 as remote DNS forwarding server.

# 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.
#
# The following line includes additional configuration files from the
# /etc/unbound/unbound.conf.d directory.
include: "/etc/unbound/unbound.conf.d/*.conf"

server:
    interface: 0.0.0.0
    do-ip4: yes
    do-ip6: no
    do-udp: yes
    do-tcp: no
    access-control: 0.0.0.0/0 allow

remote-control:
    control-enable: no

forward-zone:
    name: "."
    forward-addr: 9.9.9.9

Restart unbound to make it use the new settings. We also enable unbound.service to autostart it at boot. It is probably already enabled by denian when installed but I show how to do it in case it is not enabled.

$ sudo systemctl restart unbound.service
$ sudo systemctl enable unbound.service

To use unbound we change resolv.conf to use nameserver address 127.0.0.1 (which is localhost)

$ sudo nano /etc/resolv.conf

comment out the nameserver line add add your own:

#nameserver 213.186.33.99
nameserver 127.0.0.1

Now we try the DNS lookup by using drill to look for IP address to lethean.io

$ drill lethean.io
;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 59754
;; flags: qr rd ra ; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;; lethean.io.  IN      A

;; ANSWER SECTION:
lethean.io.     300     IN      A       198.49.23.145
lethean.io.     300     IN      A       198.185.159.144
lethean.io.     300     IN      A       198.49.23.144
lethean.io.     300     IN      A       198.185.159.145

;; AUTHORITY SECTION:

;; ADDITIONAL SECTION:

;; Query time: 141 msec
;; SERVER: 127.0.0.1
;; WHEN: Fri Jun 14 17:40:45 2019
;; MSG SIZE  rcvd: 92

141 ms is not very fast. But this was first trial after starting unbound. Now this lookup should be cached in memory so we try it again.

$ drill lethean.io
;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 15965
;; flags: qr rd ra ; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;; lethean.io.  IN      A

;; ANSWER SECTION:
lethean.io.     214     IN      A       198.49.23.145
lethean.io.     214     IN      A       198.185.159.144
lethean.io.     214     IN      A       198.49.23.144
lethean.io.     214     IN      A       198.185.159.145

;; AUTHORITY SECTION:

;; ADDITIONAL SECTION:

;; Query time: 0 msec
;; SERVER: 127.0.0.1
;; WHEN: Fri Jun 14 17:42:11 2019
;; MSG SIZE  rcvd: 92

0 ms is very good! So now it read the IP address from memory instead of asking a remote DNS server. After a while this IP address will be cleared from memory. But if many users are using the exit node many popular addresses should be stored in unbound local cache memory and user experience will get much better.

Since we had so fast default remote nameserver we can change the unbound.conf to use this nameserver to forward requests that are not cached. We commented out or original DNS IP address in /etc/resolv.conf so we can take a look again.

$ cat /etc/resolv.conf
#nameserver 213.186.33.99
nameserver 127.0.0.1

So in this example we use 213.186.33.99 in /etc/unbound/unbound.conf instead of 9.9.9.9 at forward-addr line and then restart unbound.service again. You set the nameserver that works best for you. I don't need to show how to do this. Just do it in the same way as above when you changed unbound.conf and restarted it.

Now we can reboot and try drill again afterwards to confirm everything works. You know how to do this :-)

Tinyproxy should use the DNS server that is setup in /etc/resolv.conf so you do not need to do any more configuration to make proxy users to benefit of your local DNS cache. When using OpenVPN we need to setup default DNS server to point on the exit node DNS IP address. We come to that later.

NOTE: When I was using an OVH VPS I had to do additional steps.