Ad blocking with local DNS servers and NGINX

13832 VIEWS

·

Adverts on the internet can be frustrating. When visiting popular sites you can often be overwhelmed with “clickbait” and large banner ads to drive you to different sites, generate revenue and sometimes infect your computer with spyware.

Whilst add ons like Adblock Plus do exist to help suppress the amount of adverts shown to you, these only apply on a single computer, and they require browser add ons to be installed by end users.

DNS ad blocking

A more robust and efficient way of achieving this ad blocking is to do it using your own DNS servers, and serving up “adblocked” pages using NGINX. This means it will be done on a network-wide level. It will therefore work on devices which don’t have adblock plugins available, such as certain phone and tablet devices, and provide less tracking and greater security within your network.

In this guide I will show you how to setup a basic bind installation, configure it to provide ad blocking and where to obtain updated adblock lists which you can use to frequently update your bind configuration. I’ll also explain how to set up an NGINX server running alongside bind to serve a fake page when blocked sites are being requested. This is vital, since otherwise your browser will simply hang requests and wait for them to time out, leaving to a poor user experience.

Installation of Bind

The first thing we are going to do is install both bind and NGINX on our CentOS 7 server (which you should have already built). It is not required to have both of these on the same server; we are just doing it that way for convenience. I will, however, point out which configuration files to change should you want these to be located on different servers.

The first thing we need to do is set up any additional repositories we require. In this case we only require one additional repository, epel-release, which is necessary for installing NGINX. You can install epel-release by using the following command.

yum -y install epel-release

Once we have this installed we can go ahead and install bind and NGINX.

yum -y install bind-chroot nginx

Once these have been installed we need to go ahead and configure bind. The config file we will be modifying is located in /etc/named.conf. We need to make the following changes:

listen-on port 53 { any; }; // This can be either a specific interface IP on the box, or any for all interfaces.
listen-on-v6 { none; }; // Turn off IPV6, unless required in your setup.
allow-query     { 192.168.1.0/24; }; // This permits uses in our local subnet to query this server, add all subnets that will query this server to here.
forwarders { 8.8.8.8; 8.8.4.4; }; // This tells the server to forward any requests it can’t resolve to other nameservers, in this case google’s however this could also be nameservers from your ISP.

Now that we have completed these steps, let’s go ahead and open port 53 in firewalld using the following command.

firewall-cmd --zone=public --add-service=dns # Puts the rule into the active ruleset.
firewall-cmd --zone=public --add-service=dns --permanent  # Ensure change persists after firewallsd restart.

Once permitted in the firewall go ahead and start bind and make it start at boot.

systemctl start named
systemctl enable named

We can now query our name server from another machine to ensure everything is working correctly.

[[email protected] ~]# dig @192.168.1.122 google.co.uk +noall +answer

[[email protected] ~]# dig @192.168.1.122 google.co.uk +noall +answer
; <<>> DiG 9.9.4-RedHat-9.9.4-29.el7_2.3 <<>> @192.168.1.122 google.co.uk +noall +answer
; (1 server found)
;; global options: +cmd
google.co.uk.           263     IN      A       172.217.23.35
[[email protected] ~]#

As you can see, everything is in order and our name server responded successfully.

We are now in a position to set up our ad blocking. To obtain a list domains that serve advertisements I use the following site: https://pgl.yoyo.org/as/. It offers a number of export options. The one we are interested in is the bind8 format. Export this list and put it into a file named block.conf on your name server. I do this in one command, as follows:

curl -o /etc/block.conf "https://pgl.yoyo.org/as/serverlist.php?hostformat=bindconfig&showintro=0&startdate%5Bday%5D=&startdate%5Bmonth%5D=&startdate%5Byear%5D=&mimetype=plaintext"

Next, we need to include this additional bind config file containing our ad blocked domains in our main config file at /etc/named.conf. This can be done by editing /etc/named.conf and appending this line to the bottom of the file:

include "/etc/block.conf";

Lastly, we want to create our null zone file. An example of this file can also be found at https://pgl.yoyo.org/as/null.zone.file; however, I have included this below.

Create /var/named/null.zone.file with the following content:

$TTL    86400   ; one day

@       IN      SOA     ns.example.com.      hostmaster.example.com. (
                     2016090101       ; serial number YYMMDDNN
                     28800   ; refresh  8 hours
                     7200    ; retry    2 hours
                     864000  ; expire  10 days
                     86400 ) ; min ttl  1 day
              NS      ns.example.com.
              A       192.168.1.122
*             IN      A      192.168.1.122

The IP of “192.168.1.122” is the IP of our name server, which is also running NGINX. If you chose to run your NGINX server separately from DNS your name server, please put the alternate servers IP address here.

Once you have created this file you can now restart bind to read in the changes with:

systemctl restart named

We can then test the changes by querying what should be a blocked domain and ensuring the IP we specified above in the zone file is returned.

[[email protected] ~]# dig @192.168.1.122 101com.com +noall +answer
; <<>> DiG 9.9.4-RedHat-9.9.4-29.el7_2.3 <<>> @192.168.1.122 101com.com +noall +answer
; (1 server found)
;; global options: +cmd
101com.com.             86400   IN      A       192.168.1.122
[[email protected] ~]#

As you can see our own IP address is returned. This bind server is now configured and ready for use.  

Configuration of NGINX

Our last step is to configure NGINX to serve a blank page when content is requested from a blocked domain. Our NGINX configuration can stay largely as default. We just need to modify a few things in /etc/nginx/nginx.conf under the “server” subsection. Your server subsection should end up looking like the example below.

 server {
       listen 80 default_server;
       server_name  _;
       #Redirect images to blankimg and catch all our traffic.
       rewrite .+?(png|gif|jpe?g)$ /blankimg last;
       rewrite ^(.*)$ / last;

       location / {
              #Return 204 - no content.
              return 204;
       }

       location /blankimg {
              empty_gif; # See http://nginx.org/en/docs/http/ngx_http_empty_gif_module.html
       }
}

Now we can start NGINX, make it run at boot and permit http traffic through the firewall using these commands:

systemctl start nginx
systemctl enable nginx

firewall-cmd --zone=public --add-service=http # Permit http traffic in the active ruleset
firewall-cmd --zone=public --add-service=http --permanent # Make the above change persist a restart of firewalld

You can now hit this and ensure it is working correctly.

[[email protected] ~]# curl -vvv http://101com.com

HTTP/1.1 204 No Content

I have removed output that is not relevant; however, as you can see above, a “204 No Content” error is returned.

Final Thoughts

Ad Blocking can vastly improve your online web browsing experience. It can also make for a better experience when doing other things such as playing games on a mobile phone, as intrusive pop up adverts will be blocked there, too. However, it is important to remember that this can be the only revenue stream for many free content providers, so ad blocking should be done with care. If adverts are not intrusive it is often a good idea to not block this content and continue supporting content creators and keeping the content you enjoy free.


Casey Rogers is an experienced Senior Infrastructure Engineer with more than 8 years’ experience working with some of the UK’s biggest companies and multinationals.Largely self-taught, Casey has long had an interest in IT and has been brought up around technology.


Discussion

Click on a tab to select how you'd like to leave your comment

Leave a Comment

Your email address will not be published. Required fields are marked *

Menu