There are numerous ways to block advertisements in your browser, but what if you could block them on the router? Here’s how to use the DD-WRT firmware and deliberate “DNS poisoning” to block ads for every device on your network.

Overview

Update: Guide updated to reflect the feedback provided by commenters and updated the anti-ads pack with the newer pixel-server executable and a changelog.

The first question on everyone’s mind right now is “why not just use ad-block?”

For a lot of people there simply isn’t a reason, especially with chrome’s new ability to replicate the extensions you use to every computer you are running chrome on.

The answer lies somewhere between the reduced overhead of not having to teach all of the users on your network about ad-block (I’m talking to you mom, sis, granny and office secretary) and the convenience of not being bothered with it on every computer you setup. That is assuming that there are going to be some computers on your network that you’re not going to configure your personal environment on (for example “core servers” or VM’s).

Note: Even though i use the method below on my home router, I found ad-block to be an excellent addition to it, and I do recommend using both methods in conjunction. also if you don’t have a DD-WRT router using ad-block is more them enough. In fact, I like the program so much, I donated to its developer and i encourage everyone to do so, to keep it’s development going.

How does it work?

Essentially this works by deliberately poisoning our DNS to return a specific IP for domains in the an unapproved list. This unapproved list will contain domain names of sites that are responsible exclusively for delivering advertisement content, so we won’t miss them much.

We will setup a secondary HTTP server on the router to serve a transparent one pixel image, as the answer for any URL request. In conjunction with the DNS “wrong” resolve, this will cause the network clients to request the content from our internal pixel-server and get a blank image in response.

To generate the unapproved list, we will create one personal list in conjunction to two dynamically downloaded lists. the dynamic lists are the MVPS host file and the Yoyo domain list, together they hold a very extensive list of advertisement sites. By leveraging these lists, we are left with the responsibility of just adding the delta of sites that are not already in one of them, in our personal list.

We will also setup a “whitelist” for domains we don’t want to be blocked for any reason.

Prerequisites and assumptions

Patience young one, this is a long read.

This procedure was created and tested on DD-WRT (v24pre-sp2 10/12/10 mini r15437 ), as such you should already have this version or later installed on your router to use it. More information is over on the DD-WRT site.

), as such you should already have this version or later installed on your router to use it. More information is over on the DD-WRT site. For ease of explanations sake, it is assumed the router has been restored to it’s “factory defaults” or that the settings used have not changed from their “out of the box” presets since then.

The client computer is using the router as the DNS server (this is the default).

Space for JFFS (when in doubt, I recommend using the mini version of DD-WRT).

version of DD-WRT). It is assumed that your network is *already set and that it’s a class C (one that has a subnet of 255.255.255.0) as the last IP on that class C network (x.y.z. 254 ) will be assigned for the pixel-server program.

) will be assigned for the pixel-server program. The willingness to install winSCP.

*The script will not be able to adjust the block lists after the first run until the next refresh cycle (3 days).

Credits

Update: Special thanks to “mstombs” for the great piece of C code without his work all this wouldn’t be possible, “Oki” for compiling the Atheros compatible version and quote ;-) and “Nate” for helping with the QA-ing.

While there was a lot of work to perfect this procedure on my end, the inspiration for it was ignited by the guys over at the DD-WRT forum and some of the foundations of this guide can be found at “ad-blocking with DD-WRT revisited (simple)”, “pixelserv without Perl, without any jffs/cifs/usb free“ and “Flexion.Org Wiki on DNSmasq“ as well as others.

Lets get cracking

Enable SSH for SCP access

By enabling SSH, we in turn give ourselves the ability to connect to the router using the SCP protocol. with that enabled, we can then use the winSCP program to visually navigate the folder structure of the router (as we will see later).

To do this, using the webGUI, go to the “Services” tab. Find the “Secure shell” section and click the “Enable” radio button for the SSHd setting.

Once that’s done, the webGUI should look as below and you can click on “Save” (don’t apply yet).

Enable JFFS

In order to make this setup in a way that would be stable, reproducible and *be a “good internet citizen”, we will use JFFS to store as much of the configurations as possible. There are other ways to do this without enabling JFFS, if you cant due to space limitations, but they are not covered here.

*other methods have your router download the pixel-server executable and dynamic lists every time the script is run. as this puts a strain on the servers holding the lists and executable and this costs money to someone, this method tries to avoid it if possible.

If you don’t already know what is JFFS, this explanation, taken from DD-WRT’s wiki entry about JFFS should clear things up:

The Journaling Flash File System (JFFS) allows you to have a writable Linux File System on a DD-WRT enabled router. It is used to store user programs like Ipkg and data into otherwise inaccessible flash memory. This allows you to save custom configuration files, host custom Web pages stored on the router and many other things not capable without JFFS.

To enable JFFS on your router, go to the “Administration” tab and find the JFFS section. the picture below shows where you would find this section within the “Administration” tab.

In the JFFS2 Support section, click the “Enable” radio buttons for the “JFFS2” and (when it appears) the “Clean JFFS2” settings. Once selected, click on “Save”.

When the settings have been saved, still on the “Administration” tab, reboot the router by using the “Reboot Router” button. This will apply the settings and perform the needed “format” of the JFFS “partition”.

When the webGUI comes back from the reboot to the “Administration” tab, wait for an additional half a minute and refresh the page.

If successful, you should see that your JFFS mount has some free space as in the picture.

Pixel server setup

Download and extract the anti ads pack for dd-wrt zip archive which contains the pixel-server executable (we are not taking credit, only avoiding “hot linking”), the ad-blocking script (written by yours truly) and the personal-domain-list created by “Mithridates Vii Eupator” and I.

It is time to get the files into the JFFS mount on the router. to do this, install winSCP (it is a “next –> next –> finish” type of a setup) and open it.

In the main window, fill in the information like this:

Host name: your router’s IP (default is 192.168.1.1)

Port number: leave unchanged at 22

User name: root (even if you changed the username for the webGUI, the SSH user will always be *root* )

Private key file: leave blank (this is only necessary when you create a key-pair based authentication which we haven’t)

File protocol: SCP

We also need to disable “Lookup user group” as shown below (thanks mstombs for pointing this out) because winSCP is expecting a full blown Linux on the other side which DD-WRT’s developers, despite all of there excellent work, were unable to provide (mainly because there simply isn’t enough space). If you leave this checked, you will encounter scary messages when you connect and save edited files.

Select Advance, and then uncheck “Lookup user groups”.

While it is optional, you may opt to save the settings now for later use. If you do choose to save the settings which is recommended, it is also recommended (despite the outright cries from the “security paranoid” asylum that we are desecrating the very existence of SSH) that you save the password.

Then your main window will look like in the picture, and all you’ll have to do to connect to the router is double click the entry.

As this is the first time you will be connecting to the router, winSCP will ask if you are willing to trust the fingerprint of the other side. Click “Yes” to continue.

DD-WRT’s developers have implemented a Banner welcome message with some info about the firmware you have installed. once red, click on the “Never show this banner again” checkbox and “Continue”.

Once connected, navigate your way to the top level folder (A.K.A. root “/”) and then go back down to “/jffs” as that is the only permanently writable place on the router’s filesystem (“/tmp” doesn’t survive reboots and the rest are read-only).

Create a new folder, by hitting F7 or right clicking a blank spot, hover over “New” and click “Directory”.

Name the new directory “dns”. we create this directory in order to keep things in the jffs directory organized for future use and because we are mostly changing how the DNS service works.

Copy the “pixelserv” and “disable-adds.sh” files from the anti-ads-pack-for-dd-wrt zip archive, by selecting them (use the “insert” key), hitting “F5” and then “Copy”.

Note: If your router is Atheros based (you can check this on the DD-WRT wiki) you will need to use the pixelserv_AR71xx provided by Oki and included in the pack and rename it to “pixelserv” before continuing.

Once the files are on the router, we need to make them executable by selecting them (again use “insert”) right click then “properties”.

On the properties window click on the “X” for the “Owner” row. that will give the files execution permissions.

Router settings

Now that the stage is set, we can tell the router to run the ad-blocking script at startup.

To do this, in the webGUI go to the “Administration” tab and then the “Commands” tab.



In the “Commands” text box write the location of the script as “/jffs/dns/disable_adds.sh”, as in the picture and then click on “Save Startup”.

If successful, you should see the script has become part of the router’s startup as in the picture above.

Setting up the Personal blocked domains list (Optional)

This list enables you to add domains to the unapproved lists, if you find that the two dynamic lists don’t catch something.

To do this, there are two options, and they work in conjunction so you may use both according to what is more convenient for you.

Note: The syntax is important, As we are actually creating configuration directives that the DNSMasq daemon (the process that is responsible for DNS-name to IP translations) will use directly. As such, incorrect syntax here will cause the service to crash and leave the router unable to resolve IP addresses for domain names (you have been admonished).

In order to find the offending domain names to block you may want to use our “Find the Secret Messages in Web Site Headers” guide as a primer. The steps to finding the names of the advertisement domains are practically the same, only that in this case you are looking for an address instead of a message.

The first and admittedly more accessible way is to put the list into the “DNSMasq” configuration box in the wegGUI. This is because to add to this list one can simply access the webGUI instead of having to go “under the hood” to make changes.

Go to the “Services” tab, find the “DNSMasq” section and there find the “Additional DNSMasq Options” text-box.

In this text-box enter the lists of domains that you want to be blocked with the syntax “address=/domain-name-to-block/pixel-server-ip” as shown in the picture below:

Where in this example the “192.168.1.254” is the IP that’s generated for the pixel-server based on the “network address” of your LAN. If your network address is something other then 192.168.1.x you will have to adjust the address for the pixel-server accordingly.

When finished, click on “Save” at the bottom of the page (don’t apply yet).

The second option is to compound the list of domains that you want to block, to the “personal-ads-list.conf” file that myself and and “Mithridates Vii Eupator” have assembled. This file is part of the zip-archive you downloaded earlier and it’s a great start for both methods.

In order to use it, if necessary, use your favorite text editor to adjust the IP of the pixel-server (the same constraints as above apply here). Then simply copy it to the “/jffs/dns” directory as you have the other files. Once it’s in there you can use winSCP to edit it and add domains.

Setting up the whitelist

This is the list of domains that will be omitted from the dynamic “hosts” and “domains” lists.

This is necessary because simply blocking some domains causes sites using them to malfunction. the most noteworthy example is “google-analytics.com”.

If we block it’s domain, it will not change the fact that sites that use it, have your browser download a JavaScript that runs on events such as leaving a page. This means that for such a site your browser will try to “call home” by contacting the google domain, will not understand the reply and you will have to wait until the script times out to continue to the next page. That’s hardly a pleasant surfing experience and that is why any domain containing “google-analytics” and “googleadservices” is *hardcodedly exempt from filtering.

This list is created for you with the above mention domains, when the script is run for the first time, under the “/jffs/dns” directory.

To use the whitelist, open the file with winSCP and **perpend to the list the domains you want excluded, while being careful to not leave any blank lines (leaving a blank line will delete all the domains from all of the lists).

*While the script creates the whitelist with the domains within it on the first run, it does NOT insists on their presents for future runs. so if you feel that google should be blocked despite the aforementioned problems, you can remove the domains from the whitelist.

**You must enter the new domains you want at the start of the list. This is because of a bug with how bash interprets new lines… sorry i don’t have a work around for that yet.

Execution

This is it, it is finally time to invoke the script and see the results by simply restarting the router.

To do this from the webGUI,Under the “Administration” tab go back to “Management” , at the bottom of the page click on “Reboot router” and wait for the router to come back up.

It may take a couple of minutes for the script to perform its duties for the first time.

On WRT54Gx type of routers, you will know when the script has finished executing because it will blink the Cisco orange LED on the front of the router (other routers should have a similar “tell tail” sign).

Update: This part was *removed after it was discovered to be a non-hardware agnostic feature.

As we are trying to see the absence of elements on the web, I recommend simply surfing to a couple of sites to see the affect.

However if you want to make sure the procedure was successful the first debug step in the troubleshooting section is a great place to start with.

*It’s actually commented out so you can restore it if your sure it will not cause problems on your setup.

Enjoy!

Troubleshooting

If you run into problems there are a couple of things that you can do to check what went wrong.

Test that the advertisement domain is resolved to the pixelserv IP.

You can do this by issuing the nslookup command against the “offending” domain. For example the “ad-emea.dubleclick.com” is part of the blocked hosts from the personal list. By issuing “nslookup ad-emea.dubleclick.com” in a command prompt, the result should look like:



Where a normal unblocked answer would look like:



Do over.

To make sure that nothing with your router’s setup is clashing with the ad-block configuration, restore the router to “Factory Defaults” and try again. Once your successful add your custom changes in the hope that they don’t clash again. Make sure your client is using the router as the DNS.

Especially when using a VPN or a network that is more complex then the normal router to computer setup, it is possible that your client computer is simply not using the router as its DNS. It is very easy to see in the command above what is the DNS server the client is using, If the IP is not the same as the router, you have found the problem. Clear your personal machines DNS cache.

This is because otherwise you may still see the ads to the site your testing with, simply because your computer already knows how to get the advertisement content on its own without consulting the DNS for it. On windows this would be “ipconfig /flushdns”. Close the browser.

Sometimes the browser holds the information cached, so clearing the DNS cache as shown above doesn’t help. When in doubt reboot.

Sometimes the caches can persist and the best way to get rid of them is to reboot. Start with the router and if the problem persists, the client computer. Use syslog.

You can activate the router’s syslog daemon and then look at the messages to see if the script encounters any problems, by examining its messages. Also the script adds some command aliases to make debugging easier.

To do this go to the “Services” tab and enable the syslog daemon as in the picture below:



Note: The “Remote Server” is used when you have a listening syslog server on another machine (like with kiwi) if you don’t have one, simply leave it blank.



Once enabled, you can see the debug messages by looking at the /var/logs/messages file in a terminal.

*To see ALL messages from boot-up you can use “more /var/log/messages”.

*To see just the messages from the script in the log use the “clog” alias.

*To see the messages as they come in, in real time, use ”tail -f /var/log/messages” or by its alias “tlog”. Understand the script.

Even though I have made this YouTube video for an older version of this guide and the script, it still holds a lot of truths and explanations that are applicable to how the new and improved version works.

May the router gods be in your favor