Recursive DNS Server using Pi-hole
What is Pi-hole?
The Pi-hole® is a DNS sinkhole that protects your devices from unwanted content without installing client-side software.
In other words, a Pi-hole is a DNS server that prevents ads from loading when we attempt to load web pages.
This document
Here, we will set up Pi-hole as a recursive DNS server using Unbound.
Benefits
It will search for the authoritative DNS server for each domain name instead of asking a 3rd party. This setup will help prevent 3rd party DNS from compiling your profile based on the websites you visited and will make you safer against DNS spoofing.
Unbound
For the recursive part of the server, we will be using Unbound. Unbound is a secure open-source recursive DNS server.
You can find the official documentation here.
Step 1 - Install Pi-hole
Before proceeding, ensure that your machine has a static IP.
To install Pi-hole, just run the following command and follow the instructions.
1
curl -sSL https://install.pi-hole.net | bash
You can use the default for everything. Later, we will edit the configuration files as required.
Password
Upon installation, you should have your password on the console. If you want to change it, you can use the following:
1
sudo pihole -a -p <password>
Post install
Go to your web interface and try to log in. The web interface is on http://<server IP>/admin/
.
It should look something like this:
Step 2 - Install Unbound
To install Unbound, run the following command:
1
sudo apt install unbound -y
Unbound will only work after we configure.
For the official documentation for this setup, follow the Pi-hole documentation tutorial.
Step 3 - Configure Unbound
We need to create the following file:
1
sudo vim /etc/unbound/unbound.conf.d/pi-hole.conf
Then, we need to give it a new configuration:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
server:
# If no logfile is specified, syslog is used
# logfile: "/var/log/unbound/unbound.log"
verbosity: 0
interface: 127.0.0.1
port: 5335
do-ip4: yes
do-udp: yes
do-tcp: yes
# May be set to yes if you have IPv6 connectivity
do-ip6: no
# You want to leave this to no unless you have *native* IPv6. With 6to4 and
# Terredo tunnels your web browser should favor IPv4 for the same reasons
prefer-ip6: no
# Use this only when you downloaded the list of primary root servers!
# If you use the default dns-root-data package, unbound will find it automatically
#root-hints: "/var/lib/unbound/root.hints"
# Trust glue only if it is within the server's authority
harden-glue: yes
# Require DNSSEC data for trust-anchored zones, if such data is absent, the zone becomes BOGUS
harden-dnssec-stripped: yes
# Don't use Capitalization randomization as it known to cause DNSSEC issues sometimes
# see https://discourse.pi-hole.net/t/unbound-stubby-or-dnscrypt-proxy/9378 for further details
use-caps-for-id: no
# Reduce EDNS reassembly buffer size.
# IP fragmentation is unreliable on the Internet today, and can cause
# transmission failures when large DNS messages are sent via UDP. Even
# when fragmentation does work, it may not be secure; it is theoretically
# possible to spoof parts of a fragmented DNS message, without easy
# detection at the receiving end. Recently, there was an excellent study
# >>> Defragmenting DNS - Determining the optimal maximum UDP response size for DNS <<<
# by Axel Koolhaas, and Tjeerd Slokker (https://indico.dns-oarc.net/event/36/contributions/776/)
# in collaboration with NLnet Labs explored DNS using real world data from the
# the RIPE Atlas probes and the researchers suggested different values for
# IPv4 and IPv6 and in different scenarios. They advise that servers should
# be configured to limit DNS messages sent over UDP to a size that will not
# trigger fragmentation on typical network links. DNS servers can switch
# from UDP to TCP when a DNS response is too big to fit in this limited
# buffer size. This value has also been suggested in DNS Flag Day 2020.
edns-buffer-size: 1232
# Perform prefetching of close to expired message cache entries
# This only applies to domains that have been frequently queried
prefetch: yes
# One thread should be sufficient, can be increased on beefy machines. In reality for most users running on small networks or on a single machine, it should be unnecessary to seek performance enhancement by increasing num-threads above 1.
num-threads: 1
# Ensure kernel buffer is large enough to not lose messages in traffic spikes
so-rcvbuf: 1m
# Ensure privacy of local IP ranges
private-address: 192.168.0.0/16
private-address: 169.254.0.0/16
private-address: 172.16.0.0/12
private-address: 10.0.0.0/8
private-address: fd00::/8
private-address: fe80::/10
Save and exit vim
using esc
and the type :wq
and hit enter
Start and test your service:
1
2
sudo service unbound start;
dig google.com @127.0.0.1 -p 5335
If everything goes well, you should get the following output:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
; <<>> DiG 9.18.19-1~deb12u1-Debian <<>> google.com @127.0.0.1 -p 5335
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15988
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;google.com. IN A
;; ANSWER SECTION:
google.com. 300 IN A 142.250.200.110
;; Query time: 204 msec
;; SERVER: 127.0.0.1#5335(127.0.0.1) (UDP)
;; WHEN: Sat Dec 30 17:41:57 WET 2023
;; MSG SIZE rcvd: 55
You should also consider setting the EDNS to its recomendation, using:
1
echo edns-packet-max=1232 | sudo tee -a 99-edns.conf
EDNS (Extension DNS) is a hop-by-hop extension to DNS. This means the use of EDNS is negotiated between each pair of hosts in a DNS resolution process, for instance, the stub resolver communicating with the recursive resolver or the recursive resolver communicating with an authoritative server. J. Damas et. al 2013.
Step 4 - Configure Pi-hole
Login into your Pi-hole main page. Go to Settings->DNS
. You must uncheck any Upstream DNS Servers
and selct a custom one with 127.0.0.1#5335
. If your server is on a different network than all devices that use it, you must enable Respond only on interface ens18
. The configuration must look something like this:
Back to the terminal, disable resolvconf.conf
entry for unbound
:
1
2
3
4
sudo systemctl disable --now unbound-resolvconf.service;
sudo sed -Ei 's/^unbound_conf=/#unbound_conf=/' /etc/resolvconf.conf;
sudo rm /etc/unbound/unbound.conf.d/resolvconf_resolvers.conf;
sudo service unbound restart
Step 5 - Enable Logging
Logging can be helpful for several reasons, including debugging.
Start by editing the config file /etc/unbound/unbound.conf.d/pi-hole.conf
add the following:
1
2
3
4
5
server:
# If no logfile is specified, syslog is used
logfile: "/var/log/unbound/unbound.log"
log-time-ascii: yes
verbosity: 1
Note that the verbosity will define the amount of logging used. It works like this:
1
2
3
4
5
6
Level 0 means no verbosity, only errors
Level 1 gives operational information
Level 2 gives detailed operational information
Level 3 gives query level information
Level 4 gives algorithm level information
Level 5 logs client identification for cache misses
Now create the logging file and give it permissions:
1
2
3
4
5
6
7
8
9
10
11
sudo mkdir -p /var/log/unbound;
sudo touch /var/log/unbound/unbound.log;
sudo chown unbound /var/log/unbound/unbound.log;
echo "/var/log/unbound/unbound.log rw," | sudo tee -a /etc/apparmor.d/local/usr.sbin.unbound;
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.unbound;
sudo service apparmor restart;
sudo service unbound restart
Conclusion
In conclusion, setting up a Pi-hole as a recursive DNS server using Unbound offers several benefits, primarily focused on enhancing privacy and security. By searching for authoritative DNS servers for each domain name rather than relying on third-party DNS services, this configuration helps prevent the compilation of user profiles based on visited websites. It provides a layer of defence against DNS spoofing.
The process involves installing a Pi-hole using a simple command, ensuring a static IP for the machine, and configuring it through the web interface. Unbound, an open-source recursive DNS server, is installed and configured to work seamlessly with Pi-hole.
The configuration of Unbound involves creating a specific file with recommended settings, including adjusting EDNS to its recommended values for better compatibility. Pi-hole settings are then modified to use the Unbound server as a custom DNS server.
Additionally, enabling logging can be valuable for debugging and monitoring. By adjusting the verbosity level, users can control the amount of logging generated by Unbound.
This setup provides users a powerful tool to block unwanted content, particularly ads, while ensuring a more private and secure DNS resolution process. Overall, the combination of Pi-hole and Unbound creates a robust and efficient DNS sinkhole solution for users seeking enhanced control over their online experience.
Inspiration
This setup is inspired by Jeff’s from Craft Computing video.