Select Page
NOTE: This is a static archive of an old blog, no interactions like search or categories are current.

Regular readers here will know I patch bind with GeoIP extensions, this has served me well but my needs have now outgrown simply doing geo related replies.

I’ve for a long time had an itch to be able to do completely custom DNS, maybe respond to monitoring, or time of day, geographical location or even to work around some unbelievably annoying bugs in windows that breaks all round robin dns, this has not been possible with Bind.

PowerDNS has a backend that simply speaks via STDIN and STDOUT to any script, the documentation though is pretty shoddy but I quickly realized this is the way to go.  Once I figured out all the various weird things about PDNS and the Pipe backend I set about writing a framework to host many records in a single PDNS server – in a way that hides and abstracts all the PowerDNS details from the code

The end goal is that I would dump some Ruby code into a file on the server and it should just be served, when I get new code I just want to overwrite the old code, no restarts or anything it must just serve it.

I wanted the code to be trivially simple, something like this:

module Pdns
  newrecord(“www.your.net”) do |query, answer|
    case country(query[:remoteip])
      when “US”, “CA”
        answer.content “64.xx.xx.245”

      when “ZA”, “ZW”
        answer.content “196.xx.xx.10”

      else
        answer.content “78.xx.xx.140”
      end
  end
end

should be all that is needed to do GeoIP based serving, and really complex things like weighted random round robins that effectively work around the bugs in client resolvers like the windows one above:

        ips = [“1.x.x.x”, “2.x.x.x”, “3.x.x.x”, “4.x.x.x”, “5.x.x.x”]

        ips = ips.randomize([1,5,3,3,3])

        answer.shuffle false
        answer.ttl 300
        answer.content ips[0]
        answer.content ips[1]
        answer.content ips[2]

This code will take 5 ip addresses, shuffle them giving the first one least weight, the 2nd one most weight and return only 3 out of the 5 results, this would be impossible in Bind but trivial to imagine coding if only you could hook into the nameserver.

Anyway, so I wrote a framework that enables exactly this, the code snippets above are actual working snippets.  The code is hosted on Google Code as ruby-pdns and is at version 0.3 at present.

I’ve release tarball and RPM versions of the code, the code is publicly browsable and licensed under the GPLv2. 

At present I think I’ve documented it all fairly well with a good set of Wiki pages though the install instructions for non RPM based install leaves a bit to be desired, I’ll work on improving that.

I’ve been running this code myself serving 10’s of 1000s of queries a day and have used the technique above to work around windows bugs.  I’m looking for testers to start using the code and sending me feedback, there are groups, tickets and all set up for that on Goole Code.