This gist will explain how to create a DNS-over-TLS
bridge for the local network.
The server part will be based on: https://dfarq.homeip.net/dns-over-tls-protect-your-network-with-ubuntu/.
Install required packaages:
# Install unbound
sudo apt install unbound
# Install stubby
sudo apt install stubby
# Create initial blackhole.zone file
sudo touch /etc/unbound/blackhole.zone
Create a new unbound
config file in /etc/unbound/unbound.conf.d/dot-server.conf
and add the following content:
server:
# Base settings
interface: 0.0.0.0
access-control: your-local-network/netmask
allow use-syslog: yes
directory: "/etc/unbound"
# Increase privacy
minimal-responses: yes
# Perform prefetching of close to expired message cache entries
# This only applies to domains that have been frequently queried
prefetch: yes
# Uncomment if the file /etc/unbound/unbound.conf.d/qname-minimisation.conf does not exist
# qname-minimisation: yes
# Enable round-robin balancing
rrset-roundrobin: yes
# Required for stubby
do-not-query-localhost: no
# Required for filtering domains
include: "/etc/unbound/blackhole.zone"
# Enable extended statistics.
statistics-interval: 0
extended-statistics: yes
# set to yes if graphing tool needs it
statistics-cumulative: yes
# Forwarding everything to stubby
forward-zone:
name: "."
forward-addr: 127.0.0.1@8053
forward-addr: ::1@8053
Replace
your-local-network/netmask
by your real values.Please make sure to check the content from other files in
/etc/unbound/unbound.conf.d
as they all will be loaded into theunbound
configuration.
Restart unbound
to apply changes:
sudo systemctl restart unbound ; systemctl status unbound -l
Now configure stubby
with the config file /etc/stubby/stubby.yml
and add the following changes:
# Set the listen addresses for the stubby DAEMON. This specifies localhost IPv4
# and IPv6. It will listen on port 53 by default. Use <IP_address>@<port> to
# specify a different port
listen_addresses:
- 127.0.0.1@8053
- 0::1@8053
# Require DNSSEC validation. For releases earlier than 1.2 a trust anchor must
# be configured configured manually. This can be done with unbound-anchor.
dnssec_return_status: GETDNS_EXTENSION_TRUE
# Specify the location of the installed trust anchor file (leave commented out
# for zero configuration DNSSEC)
# dnssec_trust_anchors: "/etc/unbound/getdns-root.key"
dnssec_trust_anchors: "/var/lib/unbound/root.key"
Then comment all default upstream
servers.
Now you can add the CloundFlare DNS if you want:
# CloudFlare servers
- address_data: 1.1.1.1
tls_auth_name: "cloudflare-dns.com"
- address_data: 1.0.0.1
tls_auth_name: "cloudflare-dns.com"
Or simply uncomment Quad9 DNS:
# IPv4 addresses
## Quad 9 'secure' service - Filters, does DNSSEC, does ECS
- address_data: 9.9.9.11
tls_auth_name: "dns.quad9.net"
- address_data: 149.112.112.11
tls_auth_name: "dns.quad9.net"
## Quad 9 'secure' service - Filters, does DNSSEC, doesn't send ECS
- address_data: 9.9.9.9
tls_auth_name: "dns.quad9.net"
- address_data: 149.112.112.112
tls_auth_name: "dns.quad9.net"
# IPv6 addresses
## Quad 9 'secure' service - Filters, does DNSSEC, does ECS
- address_data: 2620:fe::11
tls_auth_name: "dns.quad9.net"
- address_data: 2620:fe::fe:11
tls_auth_name: "dns.quad9.net"
## Quad 9 'secure' service - Filters, does DNSSEC, doesn't send ECS
- address_data: 2620:fe::fe
tls_auth_name: "dns.quad9.net"
- address_data: 2620:fe::fe:9
tls_auth_name: "dns.quad9.net"
Feel free to uncomment any other available DNS servers if you need it.
You can also add cleanbrowsing.org DNS servers:
# cleanbrowsing.org server
- address_data: 185.228.168.9
tls_auth_name: "security-filter-dns.cleanbrowsing.org"
- address_data: 185.228.169.9
tls_auth_name: "security-filter-dns.cleanbrowsing.org"
I personally don't use those from
cleanbrowsing.org
so I can't give advices about them.
To finish, restart stubby
to apply changes:
sudo systemctl restart stubby ; systemctl status stubby -l
Now you can run some commands to see the result:
# Check unbound status
systemctl status unbound -l
# Check stubby status
systemctl status stubby -l
# Check systemd-resolved status
systemctl status systemd-resolved -l
# Test against not DNSSEC server
resolvectl query sigfail.verteiltesysteme.net
# Test against DNSSEC server
resolvectl query sigok.verteiltesysteme.net
# Test with nslookup
nslookup google.com
# Watch DNS activity
sudo tcpdump -vni any port 853 or port 8053
If
resolvectl
does not exist, replace it bysystemd-resolve
without thequery
argument.
There’s a nice script to pull down some malware domain lists and convert them into a format that unbound can use. It will also handle your whitelists and blacklists for you.
# Install Python PIP
sudo apt install python-pip
# Install dns-blackhole
sudo -H pip install dns-blackhole
# Install Python PIP
sudo apt install python3-pip
# Install dns-blackhole
sudo -H pip3 install dns-blackhole
Now you have to create configuration files and folder:
# Create configuration folder
sudo mkdir -v /etc/dns-blackhole
# Create whitelist file
sudo touch /etc/dns-blackhole/whitelist
# Create blacklist file
sudo touch /etc/dns-blackhole/blacklist
Now create the main config file /etc/dns-blackhole/dns-blackhole.yml
:
dns-blackhole:
general:
cache: /var/cache/dns-blackhole
log: /var/log/dns-blackhole/dns-blackhole.log
whitelist: /etc/dns-blackhole/whitelist
blacklist: /etc/dns-blackhole/blacklist
blackhole_lists:
hosts: &bh_hosts
- https://www.malwaredomainlist.com/hostslist/hosts.txt
- https://gist.githubusercontent.com/Jiab77/72c868ecebce1d0027258eeec53b5a0f/raw/0cbf0a9de37c703eb728026c6337cabf43a3e679/custom-adblock-list.txt
config:
zone_file: /etc/unbound/blackhole.zone
# {domain} will be replaced by the blackholed domain, do not change it here
zone_data: 'local-zone: "{domain}" always_nxdomain'
blackhole_lists:
hosts: *bh_hosts
Once done, you can do the initial run of dns-blackhole
:
sudo dns-blackhole
You should get a similar result:
/usr/local/lib/python3.6/dist-packages/dnsblackhole/__init__.py:49: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.
yaml_config = yaml.load(f)
[!] Fetch and parse URL: https://www.malwaredomainlist.com/hostslist/hosts.txt
[!] Fetch and parse URL: https://gist.githubusercontent.com/Jiab77/72c868ecebce1d0027258eeec53b5a0f/raw/0cbf0a9de37c703eb728026c6337cabf43a3e679/custom-adblock-list.txt
If the script ran correctly, you should have a lot entries in your /etc/unbound/blackhole.zone
file:
local-zone: "0.nextyourcontent.com" always_nxdomain
local-zone: "0.r.msn.com" always_nxdomain
local-zone: "000.gaysexe.free.fr" always_nxdomain
local-zone: "000free.us" always_nxdomain
local-zone: "000tristanprod.free.fr" always_nxdomain
local-zone: "005.free-counter.co.uk" always_nxdomain
local-zone: "006.free-counter.co.uk" always_nxdomain
local-zone: "006.freecounters.co.uk" always_nxdomain
local-zone: "007.free-counter.co.uk" always_nxdomain
local-zone: "007angels.com" always_nxdomain
local-zone: "008.free-counter.co.uk" always_nxdomain
local-zone: "008.free-counters.co.uk" always_nxdomain
local-zone: "00author.com" always_nxdomain
local-zone: "00fun.com" always_nxdomain
local-zone: "00go.com" always_nxdomain
...
To finish, create a CRON
task to refresh hosts list every nights:
sudo crontab -e
And add the following lines:
01 00 * * * /usr/local/bin/dns-blackhole
30 00 * * * /bin/systemctl restart unbound
This will run the dns-blackhole
script every nights at 00:01
then restart the unbound
service at 00:30
.
The following instructions will be based on:
- https://learn.netdata.cloud/docs/agent/packaging/installer/methods/kickstart
- https://learn.netdata.cloud/guides/collect-unbound-metrics
- https://learn.netdata.cloud/docs/agent/collectors/go.d.plugin/modules/unbound
- https://learn.netdata.cloud/docs/agent/collectors/go.d.plugin/modules/dnsquery/
- https://learn.netdata.cloud/docs/agent/collectors/python.d.plugin/dns_query_time/
bash <(curl -Ss https://my-netdata.io/kickstart.sh) all --dont-wait --disable-telemetry
This section will explain how to setup DNS monitoring.
- Module
unbound
:
# Create a new unbound config file
sudo nano /etc/unbound/unbound.conf.d/netdata.conf
Add the following content:
# enable remote-control
remote-control:
control-enable: yes
And give read permission to unbound-control
files:
cd /etc/unbound/
sudo setfacl -m user:netdata:r unbound.conf
sudo setfacl -m user:netdata:r unbound_control.key
sudo setfacl -m user:netdata:r unbound_control.pem
To finish, enable cumulative stats in netdata
:
cd /etc/netdata/ # Replace with your Netdata configuration directory, if not /etc/netdata/
sudo ./edit-config go.d/unbound.conf
And set cumulative: no
to cumulative: yes
. Once done, restart the netdata
service:
sudo systemctl restart netdata ; systemctl status netdata -l
- Module
dnsquery
:
# Move to the config folder
cd /etc/netdata
# Open config file
sudo ./edit-config go.d/dns_query.conf
At the end after # [ JOBS ]
:
jobs:
- name: unbound
domains:
- google.com
- github.com
- reddit.com
servers:
- your-local-server-ip
- 9.9.9.9
- 149.112.112.112
- 1.1.1.1
- 1.0.0.1
Replace
your-local-server-ip
by your real server IP address.
- Module
dns_query_time
:
# Install required package (python2)
sudo apt install python-dnspython
# Install required package (python3)
sudo apt install python3-dns
# Move to the config folder
cd /etc/netdata
# Open config file
sudo ./edit-config python.d/dns_query_time.conf
At the end after # ----------
:
job_name:
name: unbound
update_every: 1
priority: 60000
penalty: yes
autodetection_retry: 0
# Additionally to the above, dns_query_time also supports the following:
dns_servers: 'your-local-server-ip 9.9.9.9 149.112.112.112 1.1.1.1 1.0.0.1'
domains: 'google.com github.com reddit.com'
aggregate: no
response_timeout: 4
Replace
your-local-server-ip
by your real server IP address.
Once all the configuration is done, just restart the service to apply changes:
# Restart unbound
sudo systemctl restart unbound ; systemctl status unbound -l
# Restart netdata
sudo systemctl restart netdata ; systemctl status netdata -l
dns_query_time
:
dnsquery
:
unbound
:
In this section, I'll explain how to setup the autologin
+ screen
+ bmon
.
I can't capture the result as it will contain too many private details.
It's very simple to setup the autologin
:
# Check the getty path
which getty
# Edit the getty service
sudo systemctl edit getty@tty1
Add the following content:
[Service]
ExecStart=
ExecStart=-/sbin/agetty --autologin [username] --noclear %I $TERM
Do the following changes:
- Replace
/sbin/getty
by the path given with thewhich
command - Replace
[username]
by the username you want to autologin
You can find more details here: https://wiki.archlinux.org/index.php/Getty#Automatic_login_to_virtual_console
Normally screen
should be already installed on your systemd but if not, just run the following command:
sudo apt install screen
sudo apt install bmon
Now that all dependencies are installed, you can create a small launch script that will called when the session will automatically open:
#!/bin/bash
# Create an attached Screen session usable from SSH
screen -S physical bash -c 'bmon -o curses:gheight=4 -o curses:gwidth=45 -p eth0'
The
-o curses
arguments are used to reduce the required size to display the graph on a small TFT screen.
Save the script as physical-mon.sh
and make it executable: chmod -v +x physical-mon.sh
.
Once done, add the following content in the .bashrc
file to call it when the session is started:
# Load screen + bmon
if [ $(tty) == /dev/tty1 ]; then
for I in {5..1} ; do echo "Initializing monitor in $I seconds..." ; sleep 1 ; done
~/physical-mon.sh
fi
Now you can reboot to see the result 😁
If everything has worked correctly, you should have a running screen
session created that display the bmon
system activity 🤘
To connect on that session, run the following commands:
# Connect via SSH on the remote host
ssh user@host
# List existing screen sessions
screen -ls
# Connect on the existing session
screen -x
# To disconnect without killing the screen session
[Ctrl+a] d
You can find more details here: https://linoxide.com/linux-how-to/screen-remote-ssh/
To make it work, you need at least systemd
version 237 or 242.
I'll use the version 242 in this gist.
You can check this gist if you need have the version 237 and want to upgrade it to version 242.
You will need to edit the file /etc/systemd/resolved.conf
and add the following content:
Replace
your-local-server-ip
by your real values.
[Resolve]
#DNS=9.9.9.9 1.1.1.1
DNS=your-local-server-ip
#FallbackDNS=8.8.8.8 1.0.0.1 8.8.4.4
FallbackDNS=9.9.9.9 1.1.1.1
Domains=~.
#LLMNR=no
#MulticastDNS=no
DNSSEC=yes
DNSOverTLS=opportunistic
#Cache=yes
#DNSStubListener=yes
#ReadEtcHosts=yes
For Ubuntu 20.04.x, change
DNSOverTLS=opportunistic
toDNSOverTLS=yes
.Beware the
systemd
version might be 245 or upper.
Now you can restart the service:
sudo systemctl enable --now systemd-resolved ; systemctl status systemd-resolved -l
Create required symlink
:
sudo ln -sfvn /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
Reboot to complete changes.
You should get a similar result on success with systemd-resolve --status
or resolvectl status
:
Global
LLMNR setting: no
MulticastDNS setting: no
DNSOverTLS setting: opportunistic
DNSSEC setting: yes
DNSSEC supported: no
Current DNS Server: [REDACTED]
DNS Servers: [REDACTED]
DNS Domain: ~.
DNSSEC NTA: 10.in-addr.arpa
16.172.in-addr.arpa
168.192.in-addr.arpa
17.172.in-addr.arpa
18.172.in-addr.arpa
19.172.in-addr.arpa
20.172.in-addr.arpa
21.172.in-addr.arpa
22.172.in-addr.arpa
23.172.in-addr.arpa
24.172.in-addr.arpa
25.172.in-addr.arpa
26.172.in-addr.arpa
27.172.in-addr.arpa
28.172.in-addr.arpa
29.172.in-addr.arpa
30.172.in-addr.arpa
31.172.in-addr.arpa
corp
d.f.ip6.arpa
home
internal
intranet
lan
local
private
test
Link 3 (wlp2s0)
Current Scopes: none
LLMNR setting: yes
MulticastDNS setting: no
DNSOverTLS setting: opportunistic
DNSSEC setting: yes
DNSSEC supported: yes
Link 2 (enp3s0)
Current Scopes: none
LLMNR setting: yes
MulticastDNS setting: no
DNSOverTLS setting: opportunistic
DNSSEC setting: yes
DNSSEC supported: yes
Now to verify that everything is working correctly, you'll have to run some commands:
# Check systemd-resolved status
resolvectl status
# Check local resolver status
sudo ss -lntp | grep '\(State\|:53 \)'
# Test against not DNSSEC server
resolvectl query sigfail.verteiltesysteme.net
# Test against DNSSEC server
resolvectl query sigok.verteiltesysteme.net
# Flush DNS cache
sudo resolvectl flush-caches
# Watch standard DNS port (should output local resolver)
sudo tcpdump -vni any port 53
# Watch secure DNS port (should output real queries)
sudo tcpdump -vni any port 853
journalctl -f | grep systemd-resolved
- https://wiki.archlinux.org/index.php/Systemd-resolved
- https://askubuntu.com/questions/1092498/dns-over-tls-with-systemd-resolved
- https://fedoramagazine.org/use-dns-over-tls/
- https://dfarq.homeip.net/dns-over-tls-protect-your-network-with-ubuntu/
- https://www.linuxbabe.com/ubuntu/ubuntu-stubby-dns-over-tls
- https://nlnetlabs.nl/documentation/unbound/howto-statistics/
- https://learn.netdata.cloud/docs/agent/packaging/installer/methods/kickstart
- https://learn.netdata.cloud/guides/collect-unbound-metrics
- https://learn.netdata.cloud/docs/agent/collectors/go.d.plugin/modules/unbound
- https://learn.netdata.cloud/docs/agent/collectors/go.d.plugin/modules/dnsquery
- https://learn.netdata.cloud/docs/agent/collectors/python.d.plugin/dns_query_time/
- https://github.com/Laicure/HostsY_hosts
- https://github.com/Laicure/HostsZ
- https://www.quad9.net/support/faq