The function of a DNS resolver is plain and simple: convert a domain-name into an ip-address. It starts by requesting your local operating system for an answer, which in turn forwards it to a router. The DNS resolvers configured there, which are probably some public or those of your ISP, do the rest of the work (this is overly simplified). A lot (probably all), resolvers log these request and accompanied meta-data (Google, for example, is very clear about what they log).

This means that these providers know exactly when you're visiting which websites from which IP. Apart from the fact I simply don't like this info to be logged, because we know a lot of these companies see the value of our data, setting up your own DNS resolver might also provide a nice speed improvement.

Setting up your DNS resolver using Bind9

To get this going you'll need:

  1. A client machine (All OS'es are allowed);
  2. A server machine running a Linux distribution (Ubuntu or Debian for example), on which you've got root access.
If that's the case, just follow the steps below.

1. Preparation on server

First of all, make sure to create a back-up of the following files/folders (if they exist):

/etc/resolv.conf
/etc/dhcp/dhclient.conf
/etc/bind

Also, make sure the required packages are installed:

apt install bind9 bind9utils

2. Setting up bind9 on server

Avoid DNS aplification attacks, ensure your resolver is not open!

Please keep in mind an open DNS resolver can be used for attacks. Therefore, you have to close your resolver either by:

  1. In the config example below, replace the any;-keyword with a list of your ips, like: 1.2.3.4; 2.3.4.5; for the definitions starting with allow-, or;
  2. Add firewall rules to allow a list of your IPs.

To set up the config, we'll change the /etc/bind/named.conf file as follows:

// This is the primary configuration file for the BIND DNS server named.
//
// Please read /usr/share/doc/bind9/README.Debian.gz for information on the
// structure of BIND configuration files in Debian, *BEFORE* you customize
// this configuration file.
//
// If you are just adding zones, please do that in /etc/bind/named.conf.local

//include "/etc/bind/named.conf.options";
include "/etc/bind/named.conf.local";
include "/etc/bind/named.conf.default-zones";

// Set up our personal DNS resolver
options {
directory "/var/cache/bind";
dnssec-validation auto;
auth-nxdomain no;

// Either replace 'any' with a list of IPs you allow requests from, or add firewall rules
allow-recursion { any; };
allow-query-cache { any; };
allow-query { any; };

listen-on port 53 {
127.0.0.1;
1.2.3.4;
};
listen-on-v6 port 53 {
::1;
1:2:3:4;
}
};

logging {
channel default_file {
file "/var/log/bind/default.log" versions 3 size 5m;
severity dynamic;
print-time yes;
};

channel general_file {
file "/var/log/bind/general.log" versions 3 size 5m;
severity dynamic;
print-time yes;
};

channel queries_file {
file "/var/log/bind/queries.log" versions 3 size 5m;
severity dynamic;
print-time yes;
};

category default { default_file; };
category general { general_file; };
// Comment out the line below to enable logging all requests
// category queries { queries_file; };
};

Then manually set up the logging directory:

mkdir /var/log/bind
chown bind:bind /var/log/bind

Finally it's simply a matter of enabling the service:

systemctl enable bind9
systemctl start bind9

3. Set your server as primary DNS resolver

In /etc/dhcp/dhclient.conf change the following line:

#prepend domain-name-servers 127.0.0.1;
prepend domain-name-servers 127.0.0.1;

3. Testing on server

To test if your DNS resolver is working properly, simply request a domain locally:

dig perfacilis.com @127.0.0.1

Inspect the output to see if there are no errors and if one or more IP's are returned.

4. Block access (avoid open resolver) on server

As stated above, you have to avoid being an open resolver, since open resolvers can be used in attacks. Therefore there are two methods to only allow one or more IP's.

a. Using iptables

If you'r using an iptables-firewall, I highly recommend setting the permissions there. Simply add a role to allow acces to one or more specific IP's:

# Change the list of your IP's to your liking
iptables -A INPUT -p udp --dport 53 -s 1.2.3.4,4.3.2.1 -j ACCEPT
ip6tables -A INPUT -p udp --dport 53 -s 10:20:30:40,40:30:20:10 -j ACCEPT

b. Using bind configuration

If you're not using iptables, you can allow access by replacing the any-keyword with a list of your IP's in named.conf. Do this for all definitions starting with allow-: and add a ";" after every IP:

  allow-query {
::1;
127.0.0.1;
1.2.3.4;
4.3.2.1;

};

5. Testing on client

Finally, to test if your DNS server is accepting the connection and returns a proper answer, request a domain using your client. Don't forget to change the 127.0.0.2 with the IP of your DNS server:

dig perfacilis.com @127.0.0.2

Again, everything works, when the output has no errors and returns one ore more IP's.

Using the DNS resolver

As a starter I suggest to change the DNS settings of your router. The manual of your router probably has this covered, otherwise Google has. When your router requires a secondary DNS, just use your resolver's IP again or, if that doesn't work, use some public provider which you trust most (I suggest 1.1.1.1). This covers all requests made from your home network.

I suggest manually setting the DNS servers on Wifi-based clients if you're using them at other locations than your home network. Please avoid using any apps that claim to set the DNS-records for you, since they're probably just a VPN service which will log your activity as well. So, just use the built-in settings where possible.

A note on Google Chrome

Chrome as sort of a built in DNS resolver, which you manually need to disable. To do so, go to Settings → Advanced → "Use a prediction service to load pages more quickly" and disable the checkbox.

Conclusion

Using your own DNS adds a bit more privacy to your internet activity, since DNS-requests can no longer be logged by your ISP or the public DNS service you were using. They will however still be logged by the website or service you're visiting.

A downside on DNS servers in general is that the requests are in plain text, which means they're susceptible to 'man in the middle'-attacks (MITM). In theory, your ISP could still be sniffing the packets (and even modify them to route requests trough their own servers, but if that's the case you have much larger trust issues) to find out the domain's you're visiting. Also, the response contains the domain you're visiting, thus will only be unreadable for others on the line if the response is using TLS (e.g. https).

Other solutions like "DNS-over-TLS" or "DNS-over-HTTPS" might be a solution to entirely prevent MITM-attacks, but this needs to be investigated first.

Meanwhile, just remember privacy doesn't really exist on the web.

Sources