To Protect and Surf (dnsmasq and Whitelists)

Contrary to popular rumor, I am still alive and very busy – from about October of last year until last month I have been buried at work (a good thing in this economy!). Maybe now that I can see a little daylight, I can try to keep this blog updated a little more frequently. Enough with the excuses and on with the post.

The only person in this house that likes to spend more time on the computer than me is my 4 year old son. Most of the time he is content to play an old copy of Monster Truck Madness 2 that I picked up years ago, but he also likes to spend time at Dan-Dare.org, Playhouse Disney, PBS Kids, and several other sites. The problem (other than trying to limit his time on the computer) is that he also likes to explore. When he gets bored just playing the games, he's off checking out what each menu item and dialog box does. He has explored all the configuration options in the monster truck game, and he is always playing with the volume control applet – I've spent plenty of time trying to undo his changes on the kid's computer. Lately, he has also taken to checking out the various links on the websites he visits. A couple of times he has run in to inform us that we can get a free monster truck game, and when we go check on him he has wandered off to some obscure website. Well, it happened again today, and although I've always known I would have to take action, today was the day to do something about it.

Being the cheap bastard that I am, I needed a free solution that would keep him (or my 7 year old daughter) from visiting places on the web that I would rather not have them be for now. I decided that what I need for now is a DNS forwarder with a whitelist, so that only the sites on the list can be accessed. Although the following solution is fine for small kids, anyone with an 8088 for a brain can figure out how to get around this. Even so, it should work for us for the next few years.

A little surfing pointed me to dnsmasq, a very popular dns forwarding server. A little more research indicated that using it to whitelist domains was not easy – there is no built-in way to do it. I found someone who listed a source patch to make it happen, but I didn't want to go to that extreme if I could avoid it. Despite this, I went ahead and installed it on my file server (running Ubuntu, of course) using sudo apt-get install dnsmasq. Looking at all the options in the man page and in the /etc/dnsmasq.conf file was overwhelming at first, but it didn't take too long to figure things out. One of the things I discovered was that you can assign specific outside DNS servers for specific domains. I realized that if I blocked off any other way for it to resolve domain names except for this feature, I could use it like a whitelist! A little experimenting proved that it did indeed work. Here is the dnsmask.conf that I am using right now:


# Add other name servers here, with domain specs if they are for
# non-public domains.

The first few lines do the actual configuration of dnsmasq, domain-needed & bogus-priv block Windows machines from passing noise traffic, log-queries & log-facility tell dnsmasq to log all DNS requests to the /var/log/dnsmasq.log file (useful for determining the domains required by websites, but this can be turned off to save space), no-resolv tells it to ignore the resolv.conf file which usually lists the outside DNS servers to use, and finally interface tells the service which network interface to bind to.

The rest of the “server” lines implement the whitelist, telling dnsmasq to look for the specified domain's IP address using the specified DNS server. In this case, I simply pointed to the DNS server in my local network's router ( Any other domains are simply returned as being invalid. To populate this list, I simply attempted to browse to the sites my children visit, and then looked in the /var/log/dnsmasq.log file to see what domains were being requested, then entered them into the dnsmasq.conf file. After each update to the configuration file, I needed to sudo /etc/init.d/dnsmasq restart to get the service to re-read the file.

The final step was to change the DNS server address on the kid's computer to point to the file server's IP address, and that was it – now anytime they “accidentally” try to access a domain not in the list, they get a message saying the domain was not found. Of course any computer-savvy person could simply set the DNS server to something else (like OpenDNS!), but it will probably be a few years before my kids figure that out. If they want to visit someplace new, I have to intervene (which is what I want). In a few more years, I will have to be more creative to keep ahead of the kids and to keep my workload down updating the list – but for now this works for me.

So hopefully, if there are other people like me searching for a way to add whitelisting to their dnsmasq forwarders, maybe this post will be a starting point. If you have any questions, go ahead and leave me a comment or send me an email, I'll do my best to help. And maybe if things slow down a little there will be more frequent posting around here as well.


Unknown said...

nice post! I'm using it right now, just a question: do you think is there a way to make the white-list more configurable for example could we whitelist all the domains with a specific name in it something like *linux*.com?

teknynja said...

The man page for dnsmasq doesn't indicate that wildcards can be used in the domain names for the server option - but you can always give it a try. If it works, be sure to post another comment here to let us know.

I have often thought about creating a small script to make maintaining the list a little easier, but since this is just a short-term solution, I probably won't spend too much time worrying about it, and it wouldn't really address you issue, either.

Thanks for stopping by!

Unknown said...

This is EXACTLY what I needed. I'm surprised more parents aren't clamoring for this. I use OPENDNS's home service, but it is limited to 50 domains. Considering all the Microsoft that needs to be open for Windows 7 to even function, I quickly ran out.

Darren Wiebe said...

Thanks, this is exactly what I was looking for. I built one using perl but was having some trouble. Using dnsmasq is so much easier! If somebody is interested in an interface to manage the list please visit my website and post a comment. I'm writing one based on php and mysql or else using openoffice base. I'm not going to bother releasing it if there's not interest though.

Anonymous said...

Thanks for the writeup. It's actually really interesting to see how much even good websites (like pbskids) have so much other tracking and side requests when kids are playing.

Next item I think will be to implement a full gateway to be able to throttle the kids and even track usage...that's when they are teenagers probably :-)

I keep a tail -f /var/log/dnsmasq.log running to see the recent requests when my kids want a page to load and then I add using this in my bash aliases:

add_dns() {
echo adding $1
echo server=/$1/ | sudo tee -a /etc/dnsmasq.conf
sudo /etc/init.d/dnsmasq restart

Anonymous said...

Seems like you could use iptables to drop all dns traffic from the inside interface going out and then only local dns would resolve. That way even static dns entries and local "hosts" file wouldn't matter.

Varrin at sugargroup dot net said...

Just wanted to thank you for posting this. It has been very helpful to me. I'm not done with my setup yet, but I'm combining your idea with the last comment (basically have the router force redirect all port 53 to the dnsmasq machine) on a separate router for the kids (el-cheepo w/DD-WRT) to put them on their own network. Takes a lot of domain names to make it all work right but we're moving in the right direction here. Thanks again!

Template design by Amanda @ Blogger Buster