-
Thom May’s “Sinkholing with PowerDNS Recursor” made me wonder why I run both a Pi-hole and our own Unbound DNS resolver. Perhaps I could implement blocklists and recommended exceptions using only Unbound configuration?
Our Pi-hole currently serves two purposes:
- It runs its built-in DHCP server so every device connecting to our network uses the Pi-hole’s DNS server rather than my ISP’s DNS servers (as this isn’t configurable on my router).
- It runs its own FTLDNS server to block access to domains.
As Thom points out in his post, given only those two roles and the fact I’m already running Unbound, the required tech stack for the Pi-hole (PHP, Lighttpd, Dnsmasq, etc.) seems excessive.
I decided to replace the Pi-hole with only two pieces of software:
- Use ISC DHCP as a standalone DHCP server, replacing the Pi-hole’s Dnsmasq-based DHCP server.
- Use the existing Unbound DNS server to block unwanted domains.
The Firebog’s “The Big Blocklist Collection” contains a curated list of domains to block, all in the following format:
0.0.0.0 some.bad.domain.here 0.0.0.0 another.bad.domain.here
In order to block these domains with Unbound, we can use the
local-zone
andlocal-data
configuration options. The documentation forlocal-zone
’sredirect
type contains the following example:It can be used to redirect a domain to return a different address record to the end user, with
local-zone: "example.com." redirect
andlocal-data: "example.com. A 127.0.0.1"
queries for www.example.com and www.foo.example.com are redirected, so that users with web browsers cannot access sites with suffix example.com.We’ll copy Pi-hole’s unspecified IP blocking strategy and return
0.0.0.0
for any A record lookups and::
for any AAAA record lookups:Following RFC 3513, Internet Protocol Version 6 (IPv6) Addressing Architecture, section 2.5.2, the address
0:0:0:0:0:0:0:0
(or::
for short) is the unspecified address. It must never be assigned to any node and indicates the absence of an address. Following RFC1122, section 3.2, the address0.0.0.0
can be understood as the IPv4 equivalent of::
.So to block the two example domains above, we would need the following Unbound configuration:
local-zone: "some.bad.domain.here." redirect local-data: "some.bad.domain.here. IN A 0.0.0.0" local-data: "some.bad.domain.here. IN AAAA ::" local-zone: "another.bad.domain.here." redirect local-data: "another.bad.domain.here. IN A 0.0.0.0" local-data: "another.bad.domain.here. IN AAAA ::"
We can do this by stitching together some basic command-line tools:
curl -sSf "https://v.firebog.net/hosts/static/w3kbl.txt" | # Download a blocklist grep '^0\.0\.0\.0' | # Filter out any comments, etc. that aren't rules tr -d '\r' | # Normalize line endings by removing carriage returns sort -u | # Remove any duplicates awk '{print "local-zone: \""$2".\" redirect\nlocal-data: \""$2". IN A 0.0.0.0\"\nlocal-data: \""$2". IN AAAA ::\""}' | # Convert to Unbound configuration
(You can find my full script to download and re-format all ticked blocklists on GitHub.)
As the blocklists contain domains which break essential functionality when blocked, we want to explicitly allow any domains on Anudeep’s list of exceptions.
To do this, we can use the
always_transparent
type oflocal-zone
:Like transparent, but ignores local data and resolves normally.
So, if we wanted to allow traffic to
some.bad.domain.here
even though it is already in our configuration, we need to add the following to our Unbound configuration before our blocklist:local-zone: "some.bad.domain.here." always_transparent
This will ensure we ignore our
redirect
tolocal-data
and look the domain up normally.Again, we can do some basic scripting to convert the list into configuration for us:
curl -sSf "https://raw.githubusercontent.com/anudeepND/whitelist/master/domains/whitelist.txt" | sort -u | # Remove any duplicates awk '{print "local-zone: \""$1".\" always_transparent"}' # Convert to Unbound configuration
If we save those two lists into separate configuration files called
01-safelist.conf
and02-blocklist.conf
under/etc/unbound/lists.d
, we caninclude
them in our Unboundserver
definition (e.g. under/etc/unbound/unbound.conf.d
):server: # ...other configuration here # Include blocklist and safelist include: /etc/unbound/lists.d/*.conf
We can use
unbound-checkconf
to ensure we don’t have any syntax errors andservice unbound reload
to load our new configuration if you’re usingcontrol-enable
, otherwiseservice unbound restart
.We can test this by doing a lookup of a blocked domain with dig:
~> dig @127.0.0.1 doubleclick.net +short 0.0.0.0 ~> dig @127.0.0.1 doubleclick.net AAAA +short ::
And check that any exceptions still return results:
~> dig @127.0.0.1 cdn.optimizely.com +short cdn.o6.edgekey.net. e5048.dsca.akamaiedge.net. 23.59.68.248
And with that, I could run
pihole uninstall
. -
I spent a good part of the week working with The Scale Factory to migrate a project to AWS Fargate using the CircleCI Amazon Elastic Container Registry and Elastic Container Service Orbs.
It all felt rather familiar given how similar Fargate is to Hashicorp Nomad and my experience kicking off a migration to Nomad at Altmetric.
Matt wrote Rocksteady to handle orchestrating jobspec updates when deploying but thankfully, this is provided out-of-the-box by the AWS ECS Orb’s
deploy-service-update
job.After all these changes, I’m hoping I will have cut down the total time to deploy (meaning from the start of our CI build to running our test suite, deploying to staging and then deploying to production) from over 34 minutes to 13 minutes.
-
After a bad week on the Stalk Market, I have now spent my entire life savings in bells on turnips.
Weeknotes 32
By Paul Mucur,
on