Skip to content

Instantly share code, notes, and snippets.

@anapsix
Last active August 29, 2015 14:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anapsix/8babc0e4a943c8485ca1 to your computer and use it in GitHub Desktop.
Save anapsix/8babc0e4a943c8485ca1 to your computer and use it in GitHub Desktop.
Check an IP Address agains Bogons list by turning it into an integer
#!/usr/bin/env ruby
#
# @author: Anastas Dancha <anapsix@random.io>
# @note: This script checks given IPv4 address against Bogons list
# by turnning IPs into integers, IP Ranges into integer ranges
# and using integer comparison.
# @note: Bogons list is retrieved during runtime from http://www.team-cymru.org
# @note: using binary math is way cooler,
# but integers are easier to understand.
# @note: make sure to have required gems installed
# gem install --no-ri --no-rdoc rest-client colorize
#
require 'ipaddr'
require 'rest-client'
require 'colorize'
# Expect first argument to be an IP address
IP=ARGV[0]
unless IP
puts "Try this: #{__FILE__} 216.252.161.5".red
exit 1
end
# turning IP to integer for simple comparison
def ip_to_int(ip)
ipi = 0
ip = ip.to_s if ip.class == IPAddr
ip.split(".").reverse.each_with_index { |v,i|
ipi += 255**(i)*v.to_i
}
return ipi
end
# Sample array of some bogon IP Ranges for offline testing
BOGONS_RANGES = [
IPAddr.new("0.0.0.0/8").to_range,
IPAddr.new("10.0.0.0/8").to_range,
IPAddr.new("100.64.0.0/10").to_range,
IPAddr.new("127.0.0.0/8").to_range,
IPAddr.new("169.254.0.0/16").to_range,
IPAddr.new("172.16.0.0/12").to_range,
IPAddr.new("192.0.0.0/24").to_range,
IPAddr.new("192.0.2.0/24").to_range,
IPAddr.new("192.168.0.0/16").to_range,
IPAddr.new("198.18.0.0/15").to_range,
IPAddr.new("198.51.100.0/24").to_range,
IPAddr.new("203.0.113.0/24").to_range,
IPAddr.new("224.0.0.0/3").to_range ]
BOGONS_INT = BOGONS_RANGES.map { |range| ip_to_int(range.first.to_s)..ip_to_int(range.last.to_s) }
# Real bogons list from Team Cymru Research NFP
REAL_BOGONS_URL = 'http://www.team-cymru.org/Services/Bogons/fullbogons-ipv4.txt'
REAL_BOGONS_LIST = RestClient.get(REAL_BOGONS_URL).split("\n").reject! { |v| v =~ /^#/ }
REAL_BOGONS_RANGES = REAL_BOGONS_LIST.map { |range| IPAddr.new(range).to_range }
REAL_BOGONS_INT = REAL_BOGONS_RANGES.map { |range| ip_to_int(range.first.to_s)..ip_to_int(range.last.to_s) }
# check a suspect ip agains a given range
def within_range?(suspect,ip)
# convert suspect to String
suspect = suspect.to_s if suspect.class == IPAddr
if ip.class != Range
# convert ip to integer range if it is an IPAddr and not Range yet
range_int = ip_to_int(ip.to_range.first.to_s)..ip_to_int(ip.to_range.last.to_s) if ip.class == IPAddr
elsif ip.class == Range
# confirm that ip is a Range of integers
range_int = ip if ip.first.class == Fixnum
# convert ip to Range of integers if it's a Range of IPAddr objects
range_int = ip_to_int(ip.first.to_s)..ip_to_int(ip.last.to_s) if ip.first.class == IPAddr
end
# compare suspect with first and last integer values of integer Range
if range_int.first <= ip_to_int(suspect) && range_int.last >= ip_to_int(suspect)
return true # if suspect is part of ip range
else
return false # if suspect if outside of ip range
end
end
# check an ip against given list
def bogon_check(ip,bogons_int_array)
bogons_int_array.each { |range_int|
if within_range?(ip,range_int) then
return true
end
}
return false
end
# do it
puts "Checking against simplified Bogons list.."
if bogon_check(IP,BOGONS_INT) then
puts "#{IP} is a bogon".red
else
puts "#{IP} is NOT a bogon".green
end
puts "\nChecking against real Bogons list.."
if bogon_check(IP,REAL_BOGONS_INT) then
puts "#{IP} is a bogon".red
else
puts "#{IP} is NOT a bogon".green
end
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment