hacker / welder / mechanic / carpenter / photographer / musician / writer / teacher / student

Musings of an Earth-bound carbon-based life form.

2 min read

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 = ["208.67.222.222", "208.67.220.220"]
  BLOCKED_RESPONSES =  {
    "67.215.65.130" => "hit-adult.opendns.com",
    "67.215.65.131" => "hit-block.opendns.com",
    "67.215.65.132" => "hit-nxdomain.opendns.com",
    "67.215.65.133" => "hit-phish.opendns.com",
    "67.215.65.134" => "hit-servfail.opendns.com",
    "67.215.65.135" => "block.opendns.com",
    "67.215.65.136" => "guide.opendns.com",
    "67.215.65.137" => "phish.opendns.com",
    "67.215.65.138" => "block.opendns.com",
    "67.215.65.139" => "guide.opendns.com",
  }

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

  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
      end
    end

    return false
  end

end