John Terenz.io
Ad Blocking with DNS
JT on 20160302
For a long time, I used the Chrome plugin Adblock Plus. But more recently I've wanted to tighten things up from a security standpoint, and one of the things I felt good about was removing all third-party Chrome plugins, including Adblock Plus. That left me with a problem though- how to continue to block ads and tracking scripts during my everyday browsing.
The immediate answer that came to mind was perhaps blocking unwanted domains
in my /etc/hosts
file. When I thought of this, I
felt like it was an awesome and original idea. But of course when I Googled
"ad blocking hosts file" I found that I was certainly not the first person
to think of this. There is a great page at
winhelp2002.mvps.org
where the author maintains a robust hosts file for just this purpose. So
problem solved for the time being. I installed this hosts file on a few of my
machines and called it a day.
Enter the iPad. I got my first iPad this past Black Friday and I've been
loving it. It's the iPad Mini 4, which I think is a perfect size. Anyhow
since I can't control the hosts file on this device without jailbreaking it,
I initially started accepting that ads and trackings scripts would load
during my browsing sessions. I use Chrome on my iPad also, because I like
Google sync and I am sticking with one cloud provider for the time being to
hold all my sensitive data (Google, that is). So using some other browser
with built-in ad blocking, even Safari, was not an option. One day when
reading Hacker News, I saw a post entitled
Adblock via /etc/hosts
. I of course wanted to read about this since it is a topic I am
familiar with. But what actually jumped out at me was a post in the comments
section talking about how this was similar to blocking ads with a DNS server
(specifically dnsmasq). My interest was piqued. So I
brew install
ed dnsmasq
and went to work figuring out how to configure it.
I have a Mac Mini desktop at my house that I keep on all the time so I can
serve media from it, ssh
into it when I'm away,
etc. I also have a box in
Digital Ocean
that I serve this site from, as well as some other stuff. At first my
instinct was to configure a DNS server on my Digital Ocean box and point my
home router at it. This posed a few problems though. Firstly, there would be
no redundancy if my DO box went down. Secondly, I didn't want to have a
public DNS server because it could be used for DNS Reflection Attacks. So I
would, at a minimum, need to whitelist my home IP. IP whitelisting is known
not to be very hard to bypass, plus if my Comcast IP changed under me, I
would be hosed.
After thinking a bit, I decided that a better solution would probably be to
make my home desktop that is always on into a DNS server for my local
network. This would cut down on latency, and not introduce security issues.
Futhermore, I decided that instead of pointing my router at my desktop for
DNS, I could just opt any device into using it (including iDevices, which
allow you to configure a custom DNS server for each wi-fi network. Problem
solved. I have a new DNS server running at 10.0.1.2
now, and I opted itself, plus my iPhone and iPad into using it to resolve.
Now, how to actually block ads. There are definitely people out there using
dnsmasq for this very thing. One interesting project is
https://pi-hole.net/ which
is basically what I set up, but using a dedicated Raspberry Pi. I wondered
how this project got a list of hosts together, so I dug into the source code
and found that they are basically using a
collection of sources
similar to the MVPS hosts file mentioned before. I went ahead and did some
research of my own and constructed my own script and collection of sources to
make a dnsmasq configuration file to my liking. It maps about 30,000 hosts to
0.0.0.0
. Here is the Ruby script (not aiming for
code quality):
require 'open-uri'
require 'set'
HOST_FILES = %w{
http://www.malwaredomainlist.com/hostslist/hosts.txt
https://adaway.org/hosts.txt
http://someonewhocares.org/hosts/hosts
http://winhelp2002.mvps.org/hosts.txt
https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt
https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt
https://s3.amazonaws.com/lists.disconnect.me/simple_malvertising.txt
}
hosts = Set.new
output = File.open('dnsmasq.blacklist.conf', 'w')
HOST_FILES.each do |file|
open(file) do |f|
while (line = f.gets) do
line = line.strip.gsub(/#.*/, '')
next if line == ''
_, host = line.split(/\s+/)
host = _ unless host
next unless host.include?('.')
next if host.include?('localhost')
unless hosts.include?(host)
hosts.add(host)
output.puts("address=/#{host}/0.0.0.0")
end
end
end
end
And here is my final dnsmasq.conf
. I did some
research here. Mostly by reading the incredibly informative default
configuration file that dnsmasq ships with. I decided to hard-code Google's
DNS servers as the upstream servers rather than my router, which allows me to
enable
DNSSEC
validation. I also disabled reading my hosts file (it's pretty much empty
now), increased the default cache size to be quite large, and enabled the
server on my local interface as well as my wireless interface so other
devices on my local network can use it. Note that you would also want to
assign a static IP for this local machine in your router (DHCP) settings so
that it doesn't change over time. Also note that the actual file generated by
my script lives separately the conf-dir
.
domain-needed
bogus-priv
dnssec
trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
dnssec-check-unsigned
no-resolv
interface=en1
interface=lo0
no-dhcp-interface=en1
no-dhcp-interface=lo0
no-hosts
cache-size=10000
conf-dir=/usr/local/etc/dnsmasq.d/,*.conf
# Google Public DNS
server=8.8.8.8
server=8.8.4.4
server=2001:4860:4860::8888
server=2001:4860:4860::8844
So that is basically it. I won't bore you with the many phases of configuring dnsmasq or searching for ad blocking blacklists. This is a journey you should undertake on your own. I've been running this new setup now for a few weeks and the results have been supurb. I'm especially pleased with how quickly sites load on my iPad and how responsive they are without all the ad bloat. And most importantly, I can feel slightly better that I'm at least making it more of a pain to build a file somewhere about my needs and wants as an American consumer. If you want to chat more about this, contact me!