Routing DNS over HTTPS Using Raspberry Pi
DNS is a protocol from the late 1980s, and today at its core DNS is still exactly the same. When it was conceived, there wasn't the same privacy focus as there is today, and one of the main drawbacks with the protocol is that queries and responses are not encrypted nor tamper proof when sent over the internet.
DNS over HTTPS is a newer take on the original DNS protocol, which routes queries over secure HTTP connections. While this is seeing some support (namely in Firefox and Windows 10), many devices on your network will continue to send DNS queries over UDP for years to come.
Contents
UDP Queries via HTTPS
I have been interested in how DNS works for a while now, and a few weeks ago started writing a DNS client/server in .NET Core. There are clients for HTTPS, TCP and UDP, any of which can be used by the server (see README for more information).
The library allows UDP DNS queries to be routed directly to a DNS over HTTPS (DoH) endpoint. If the server is set up on an IoT device like a Raspberry Pi and set as the default DNS server for the network, all UDP queries from devices on that network will be sent to your DNS provider via DoH.
In a typical home network setup your DNS requests would follow this path:
- Local Device (UDP) → Remote DNS (UDP)
The path as described above with a Raspberry Pi is:
- Local Device (UDP) → Local Pi (HTTPS) → Remote DNS (HTTPS)
This setup eliminates the ability of an entity in the middle to log and tamper with your DNS requests.
Setting Up The Server
The below guide assumes you want to use the default server implementation of Ae.Dns, which accepts UDP queries and routes them over HTTPS to the Google and CloudFlare public DNS services.
We will be using Ubuntu Server 20.04 LTS as the OS for the Raspberry Pi, but the executable itself runs on any Linux ARM x64 device (and can easily be compiled for any other target that .NET supports). These instructions assume Ubuntu for the service handling.
Getting the Server
A pre-built implementation of the server is available for linux-arm64.zip for Ubuntu on a Raspberry Pi, or linux-x64.zip for a regular x64 linux server. Here's the GitHub release.
This post assumes you will unzip the server to /home/ubuntu/dns/deploy
, but if you want to put it somewhere better such as /opt/
adjust the paths accordingly.
Ensure that the server executable is permitted to bind to port 53 using the following command:
$ setcap 'cap_net_bind_service=+ep' /home/ubuntu/dns/deploy/Ae.Dns.Console
Stop Ubuntu's DNS Server
To allow the server to listen on port 53, you need to disable the DNS server on Ubuntu:
$ sudo nano /etc/systemd/resolved.conf
[Resolve]
#DNS=
#FallbackDNS=
#Domains=
#LLMNR=no
#MulticastDNS=no
#DNSSEC=no
#DNSOverTLS=no
#Cache=yes
DNSStubListener=no # uncomment, set to no
#ReadEtcHosts=yes
Once the changes are made, restart the DNS service:
$ sudo service systemd-resolved restart
Set a DNS Server for the Pi
In order to keep your Pi able to resolve domains even when the DNS server isn't working, you'll want to tell it to use a DNS server other than your router. To do that, you should install resolvconf
:
$ sudo apt install resolvconf
Once installed, edit the following file:
$ sudo nano /etc/resolvconf/resolv.conf.d/head
And add your chosen DNS server:
nameserver 8.8.8.8
When your system next reboots, /etc/resolv.conf
will now start with your specified DNS server.
Creating a Ubuntu Service
To start the server at boot and in case of a crash, we'll create a systemd service.
I used this excellent tutorial on systemd to craft the below service definition:
$ sudo nano /etc/systemd/system/aedns.service
[Unit]
Description=aedns
After=network.target
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always
RestartSec=1
User=ubuntu # Set this to the user you want the server to run as
WorkingDirectory=/home/ubuntu/dns/deploy
ExecStart=/home/ubuntu/dns/deploy/Ae.Dns.Console
[Install]
WantedBy=multi-user.target
Then to start the service and enable it at startup:
$ sudo service enable aedns
$ sudo service start aedns
$ sudo service status aedns
You can now set the Pi's IP address as your default DNS server on your router, and all your network's DNS queries will be sent encrypted over HTTPS.
Troubleshooting
The following command can retrieve the status of the service:
$ sudo service aedns status
And this command can retrieve logs:
$ journalctl --unit aedns.service --pager-end
Blocking Adverts and Trackers
The server supports blocking adverts and trackers too using a remote hosts file.
Here are a few good ones at the time of writing:
To configure the server to use these block lists, modify config.json
included with the server to add a remoteBlocklists
property:
{
...
"remoteBlocklists": [
"https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts",
"https://mirror1.malwaredomains.com/files/justdomains",
"https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt"
]
...
}
The server will download the specified blocklists at startup. Once config.json
is updated, restart the service:
sudo service aedns restart
Manually Permitting Domains
If you would like to permit certain domains, you can do so with the allowlistedDomains
property:
{
...
"allowlistedDomains": [
"device-metrics-us-2.amazon.com",
"mobileanalytics.us-east-1.amazonaws.com"
]
...
}
Once config.json
is updated, restart the service:
sudo service aedns restart
The README in the Ae.Dns repository has code examples, and the core clients and servers are also available as packages on NuGet.
🏷️ dns https udp pi query ubuntu raspberry network device protocol core adverts trackers default local
Please click here to load comments.