For years we had an internal server running FreeBSD and a Bind config for the mere purpose of doing the internal DNS. Apart from being authoritative for one mockup-domain which contains all the sites for on our development server it was also running fake zones for many advertisement servers.
About a week ago the motherboard of this server died on me, for unknown reasons the board fails to powerup. The powerled is on but everything else fails. You will notice the smell of burning electronics in seconds when powered up. In that same amount of time the W83627DHG runs too hot to touch.
Exit server; as most of the stuff was migrated to other machines I thought we could manage well without it.
Until those nagging banners popped up in browsers not running ad-blockers. Nothing is more frustrating than the lag and slowness of a page loading too many ads from too many adservers.
We really needed the DNS blackhole back.. And as it happened there was a Raspberry Pi collection dust.
Inspired by http://jacobsalmela.com/block-millions-ads-network-wide-with-a-raspberry-pi-hole-2-0/#alternatesources I installed the Raspian OS and got to work.
Instead of running the “canned solution” which includes running a fake web server I decided to mimic my old Bind setup. However instead of bind I used PowerDNS instead, installing it on a Pi is as simple as:
apt-get install pdns-server
Add a file containing:
launch+=bind
bind-config=/etc/powerdns/bindbackend.conf
bind-config=/etc/powerdns/adservers.conf
to /etc/powerdns/pdns.d
and enabling the recursor in pdns.conf
and most of the config is done.
The solution by Jacob Salmela includes a shell script which fetches lists of known adservers from various places. On the old server I only used one: http://pgl.yoyo.org/adservers/serverlist.php and it worked fine but adding more known-bad servers is always good.
Ever since the eighties I cringe when I need to read through shell code. The only thing I took from the script is the list of servers. The rest I re-implemented in Python, it all had to change for the PowerDNS setup I had planned anyway.
The script gets the list from all the URL’s in the sources
By using a set() we automatically zap any duplicates we might have and with some search/replace and filtering we clean each line to represent a hostname.
With this list we create “adservers.conf” which contains all the lines to create fake authoritative domains for all the hosts. When a client asks for the IP of such a host we will give back 127.0.0.1. There is no need to run a webserver which actually processes the request. Browsers tend to remember to ignore requests to 127.0.0.1:80 when nothing is running there.
import requests
sources = [
'https://adaway.org/hosts.txt',
'http://adblock.gjtech.net/?format=unix-hosts',
##'http://adblock.mahakala.is/',
'http://hosts-file.net/ad_servers.txt',
##'http://www.malwaredomainlist.com/hostslist/hosts.txt',
'http://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts;showintro=0',
'http://someonewhocares.org/hosts/hosts',
'http://winhelp2002.mvps.org/hosts.txt'
]
def makezone(name):
tmpl = """zone "%s" { type master; file "/etc/powerdns/null.zone"; allow-update { none; }; };n"""
return tmpl % name
zones = open("adservers.conf", "w")
all_zones = set()
for source in sources:
print source
r = requests.get(source)
for line in r.iter_lines():
# skip # comment lines and lines with html (<)
if line.startswith('#') or "<" in line:
continue
line = line.replace("0.0.0.0", "")
line = line.replace("127.0.0.1", "")
if "#" in line:
# get part in front of #
line = line.split('#',1)[0]
line = line.strip()
if line and "." in line:
all_zones.add(line)
with open("adservers.conf", "w") as zones:
for zone in all_zones:
zones.write( makezone(zone) )
zones.close()
The code above is also on Github
This setup has been running a few days now and moving from standard PC hardware to a Raspberry PI saves both noise and energy.. Performance wise there is no real difference; the Pi can easily handle the load.
Now the only thing left to do is to move it from the desk to some place safe 🙂