Setup your own Bind9 DNS resolver

  •  
  •  

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 amplification attacks: Avoid open DNS-resolver!

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

  1. Follow the example below, define a list of trusted IPs only allow these for the allow-query , allow-query-cache and allow-recursion options;
  2. Setup firewall rules to only allow a list of IPs you trust, we'll show iptables examples below.

To set up the config, first we'll comment out the /etc/bind/named.conf.options in /etc/bind/named.conf :

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

Then in /etc/bind/named.conf.local , we'll add our own setup:

acl "trusted" {
1.2.3.4;
2.3.4.5;
localhost;
localnets;
}

// Set up our personal DNS resolver
options {
directory "/var/cache/bind";

 auth-nxdomain no;
 dnssec-validation auto;

// Avoid DNS-amplification / open resolver:
allow-recursion { trusted; };
allow-query-cache { trusted; };
allow-query { trusted; };
allow-transfer { none; };

listen-on port 53 { trusted; };
listen-on-v6 port 53 { trusted; };
};

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; };
};

As you can see, we've defined a list of "trusted" IPs, which we allow to query or server. Please make sure you either define a list here or set up firewall rules.

Optionally, you might want to relay (forward) your queries to other public DNS servers you trust by adding the lines below into the options section. If you must use forwarding servers, I'd suggest you to use 1.1.1.1 since they (seem to) not log any info.

options {
[...]

  forwarders {
    1.1.1.1; 1.0.0.1;
    2606:4700:4700::1111; 2606:4700:4700::1001;
  }

Then manually set up the logging directory:

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

To make sure you didn't make any mistakes while setting up, you can manually check the configuration files:

named-checkconf

If you see no errors, it's finally a matter of enabling and starting (or restarting) the service:

systemctl enable bind9
systemctl start bind9

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're using an iptables-firewall, I highly recommend setting the permissions there. Simply add a rule for each of your trusted IPs:

# 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 defining your IPs in an Access Control List:

acl "trusted" {
1.2.3.4;
2.3.4.5;
localhost;
localnets;

};

5. Set your server as primary DNS resolver on client

If you're running a desktop environment, you probably have to use steps b and c, on servers or machines with unmanaged connections, only step c will be enough.

a. DHCP Client configuration file (probably not needed)

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

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

Instead of prepend , use supersede to use the configured DNS exclusively.

b. NetworkManager

If you're running NetworkManager (I belief most Linux releases with a desktop environment do), you'll need to keep it from getting the DNS servers from your connection (e.g. using your router/default gateway) instead of what you've set up locally (e.g. in your dhclient.conf ).

The best wat i.m.h.o. is to create a new file to disable the DNS resolving:

printf "[main]\ndns=none" | sudo tee /etc/NetworkManager/conf.d/fixed-dns.conf

Finally restart network using systemctl restart network-manager or /etc/init.d/network-manager restart  to apply the new settings.

c. resolv.conf

Finally, once you've kept NetworkManager from screwing with your changes, or when your system doesn't run any network-manager at al (likely for server setups), you can set the DNS server(s) you want in /etc/resolv.conf .

sudo cp /etc/resolv.conf /etc/resolv.backup
echo "nameserver 127.0.0.2" | sudo tee /etc/resolv.conf

The commands above create a backup to /etc/resolv.backup and create a new file with the ip of your DNS, change that IP accordingly.

Finally restart network using systemctl restart networking or /etc/init.d/networking restart to apply the new settings.

6. 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. Your router's manual 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 (again 1.1.1.1). This covers all requests made from your home network. Keep in mind, any resolver you use will probably log your queries.

I suggest manually setting the DNS servers on Wifi-based clients (e.g. laptop) 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 that log even more of your activity. 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

Changelog

  • 2023-05-24
    • Added directory "/var/cache/bind"; to enable local cache, this significanly speeds up requests;
    • Added auth-nxdomain no; to confirm to RFC1035;
    • Added dnssec-validation auto; to avoid DNS Cache Poisoning.
  • 2022-07-25
    • Instead of defining IPs inside allow- options, we'll use an ACL;
    • Moved entire config to named.conf.local .
  • 2021-08-10
    • Removed " any " keyword from example configuration, made not being / creating an open resolver even more obvious;
    • Added " allow-transfer " entry to avoid unwanted DOS-attacks, as per given example;
    • Use " localnets " configration option for listen-on entries.
  • 2021-11-17
    • Added more elaborate instructions to override DNS server with managed network connections, e.g. NetworkManager , falling back to good ol' resolv.conf .