DDOS Protection with DNS & GeoIP

If you have a website that focuses only on specific countries you might want to have a look at this solution.
The idea behind this is, that for example something like >90% of the visitors of a website with german content come from Germany, Austria or Switzerland.
So, if you're under a DDOS attack you could try to block all other countries. Of course there will be still some DDOS traffic coming from the non blocked countries, but if you're lucky, your website will be able to handle this.

How can we do this?

We will set up a DNS server that checks from which country a request comes and then decides if it's a legit one or not. Here comes the first drawback: If a users makes a DNS request, the request won't go directly to your server, but it will go to the server of the users ISP and from there another request is made to your server. So your geoip lookup will look up the country of the users DNS server and not of the user itself. In most cases this will be ok, but when a users decides to use a different server (e.g. google is offering a public DNS service) the result of the country lookup might be wrong. (On a sidenote: google addresses this. Have a look at this german article)

Software needed

As DNS Server we will use PowerDNS, since it provides an easy to use Pipe backend (there's also a geoip backend already, but we'll make our own).
On a debian/ubuntu system you can install it with

apt-get install pdns-backend-pipe

For the backend we're using php and use the geo database from maxmind.
The client for the geodatabase can be installed with

pear install Net_GeoIP

You also need to download the actual database from maxmind: http://www.maxmind.com/app/geolitecountry (They provide a free version aswell)

DNS Setup of your original domain

I'm assuming that you're having a DNS server hosted by your provider. Normally in the zone file of your domain you have an entry like

www IN A 1.2.3.4

Now we will setup a subdomain that's handled by a different server (in this example: new-ns.placeholder.de), and point "www" via CNAME to another entry (test1.geo.placeholder.de) in the new subdomain:

$TTL 300
www IN CNAME test1.geo.placeholder.de.
geo 86400 IN NS new-ns.placeholder.de

We're also lowering the TTL of the entry to 300 seconds (which is a good idea anyways, changes made to your DNS entries will propagate much faster then)
Don't forget to increase the serial of your zone so that the slave nameservers will fetch the changes
You can either keep these changes forever, or you might want to switch between the A and the CNAME record for 'www' depending on if there's an attack or not.

Setup of PowerDNS

The configuration of PowerDNS is quite easy. Put the following into /etc/powerdns/pdns.d/pdns.local:

launch=pipe
pipe-command=/home/geodns/dns/powerdns-backend.php

query-cache-ttl=0
negquery-cache-ttl=0
cache-ttl=0

This basically tells powerdns to start the pipe backend, what script the pipe backend should use and that we don't want caching (we need to have a look at each request to check the source ip)

The backend script

So here's the content of the powerdns-backend.php script. It's far from being perfect but it should do it's job.


#!/usr/bin/php
lookupCountryCode($ip);
if(in_array($lookupCountry, $myCountries))
{
echo "DATA\t$qname\t$qclass\tA\t300\t-1\t$mySuccess\n";
}
else
{
echo "DATA\t$qname\t$qclass\tA\t300\t-1\t$myFail\n";
}
}

echo "END\n";
}

Conclusion

With this you won't block the ddos completely, but if you're lucky the remaining attack won't take your server down. The big advantage is that you're blocking (/redirecting) the traffic before it even reaches you.