April 6, 2010

“Using OpenDNS as a site filter”

Recently at work I needed a way to quickly filter out displaying links to sites that some folks might find 'unsavory' to say the least. Rather than try go find a list of 'naughty words' (which would inevitably be incomplete or quickly become out of date), I opted for re-using existing infrastructure. In this case, leveraging OpenDNS and its hordes of users to easily determine which domains are either "questionable" in content, or possibly even phishing or spam domains. I was able to quickly hack together some Ruby code that uses Net::DNS to query OpenDNS and make a decision based on their categorization whether to block or allow the domain.

The code is below, the gist of it is that OpenDNS returns a set of IPs for domains that fall into their classifications (adult, non-existent, phishing / scam, etc.), so if any query falls into that range of IPs, we can consider it blocked. Eventually, I may add a function to determine why the domain was blocked, rather than just relying on the true/false result.

require 'net/dns/resolver'
require 'net/dns/packet'

class OpenDNSFilter

  VERSION = "0.1"
  DNS_HOSTS = ["", ""]
    "" => "hit-adult.opendns.com",
    "" => "hit-block.opendns.com",
    "" => "hit-nxdomain.opendns.com",
    "" => "hit-phish.opendns.com",
    "" => "hit-servfail.opendns.com",
    "" => "block.opendns.com",
    "" => "guide.opendns.com",
    "" => "phish.opendns.com",
    "" => "block.opendns.com",
    "" => "guide.opendns.com",

  def initialize
    @resolver = Net::DNS::Resolver.new(
      :nameservers => DNS_HOSTS,
      :recursive => true,
      :retry => 10

  def blocked?(hostname)
    packet = @resolver.search(hostname)

    packet.each_address do |ip|
      puts "IP to str: #{ip.to_s}"
      if BLOCKED_RESPONSES.keys.include?(ip.to_s)
        return true

    return false