From e101e9aaed7e1a7f8acdac870fc237275ae30bd2 Mon Sep 17 00:00:00 2001 From: Chris Gahan Date: Sat, 25 Mar 2006 12:12:36 +0000 Subject: New plugin that finds out where an IP or domain is located (by looking up the IP address' owner in the ARIN whois database) --- data/rbot/plugins/iplookup.rb | 222 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 data/rbot/plugins/iplookup.rb (limited to 'data/rbot/plugins') diff --git a/data/rbot/plugins/iplookup.rb b/data/rbot/plugins/iplookup.rb new file mode 100644 index 00000000..a3f8f952 --- /dev/null +++ b/data/rbot/plugins/iplookup.rb @@ -0,0 +1,222 @@ +################################################################# +# IP Lookup Plugin +# ---------------------------- +# by Chris Gahan (chris@ill-logic.com) +# +# Purpose: +# ------------------ +# Lets you lookup the owner and their address for any IP address +# or IRC user. +# +################################################################# + +require 'socket' +require 'resolv' + +################################################################# +## ARIN Whois module... +## + +module ArinWhois + + class Chunk < Hash + def customer? + keys.grep(/^(City|Address|StateProv|(Org|Cust)Name)$/).any? + end + + def network? + keys.grep(/^(CIDR|NetHandle|Parent)$/).any? + end + + def contact? + keys.grep(/^(R|Org)(Tech|Abuse)(Handle|Name|Phone|Email)$/).any? + end + + def valid? + customer? or network? or contact? + end + + def owner + self[keys.grep(/^(Org|Cust)Name$/).first] + end + + def location + "#{self['City']}, #{self['StateProv']}, #{self['Country']}" + end + + def address + "#{self['Address']}, #{location} #{self['PostalCode']}" + end + + end + + class ArinWhoisParser + + def initialize(data) + @data = data + end + + def split_array_at(a, &block) + return a unless a.any? + a = a.to_a + + results = [] + last_cutpoint = 0 + + a.each_with_index do |el,i| + if block.call(el) + unless i == 0 + results << a[last_cutpoint...i] + last_cutpoint = i + end + end + end + + if last_cutpoint < a.size or last_cutpoint == 0 + results << a[last_cutpoint..-1] + end + + results + end + + # Whois output format + # ------------------------ + # Owner info block: + # {Org,Cust}Name + # Address + # City + # StateProv + # PostalCode + # Country (2-digit) + # + # Network Information: + # CIDR (69.195.25.0/25) + # NetHandle (NET-72-14-192-0-1) + # Parent (NET-72-0-0-0-0) + # + # Contacts: + # ({R,Org}{Tech,Abuse}{Handle,Name,Phone,Email})* + + def parse_chunks + return if @data =~ /^No match found / + chunks = @data.gsub(/^# ARIN WHOIS database, last updated.+/m, '').scan(/(([^\n]+\n)+\n)/m) + chunks.map do |chunk| + result = Chunk.new + + chunk[0].scan(/([A-Za-z]+?):(.*)/).each do |tuple| + #puts tuple.inspect + result[tuple[0]] = tuple[1].strip + end + + result + end + end + + + def get_parsed_data + return unless chunks = parse_chunks + + results = split_array_at(parse_chunks) {|chunk|chunk.customer?} + results.map do |chunks| + { + :customer => chunks.select{|x|x.customer?}[0], + :net => chunks.select{|x|x.network?}[0], + :contacts => chunks.select{|x|x.contact?} + } + end + end + + # Return a hash with :customer, :net, and :contacts info filled in. + def get_most_specific_owner + return unless datas = get_parsed_data + + datas_with_bitmasks = datas.map do |data| + bitmask = data[:net]['CIDR'].split('/')[1].to_i + [bitmask, data] + end + #datas_with_bitmasks.sort.each{|x|puts x[0]} + winner = datas_with_bitmasks.sort[-1][1] + end + + end # of class ArinWhoisParser + +module_function + + def raw_whois(query_string, host) + s = TCPsocket.open(host, 43) + s.write(query_string+"\n") + ret = s.read + s.close + return ret + end + + def lookup(ip) + data = raw_whois("+#{ip}", 'whois.arin.net') + arin = ArinWhoisParser.new data + arin.get_most_specific_owner + end + + def lookup_location(ip) + result = lookup(ip) + result[:customer].location + end + + def lookup_address(ip) + result = lookup(ip) + result[:customer].address + end + + def lookup_info(ip) + if result = lookup(ip) + "#{result[:net]['CIDR']} => #{result[:customer].owner} (#{result[:customer].address})" + else + "Address not found." + end + end + +end + + + +################################################################# +## The Plugin +## + +class IPLookupPlugin < Plugin + def help(plugin, topic="") + "iplookup [ip address / domain name] => lookup info about the owner of the IP address from the ARIN whois database" + end + + def iplookup(m, params) + reply = "" + if params[:domain] + ip = Resolv.getaddress(params[:domain]) + reply += "(#{params[:domain]} = #{ip}) " + else + ip = params[:ip] + end + + reply += ArinWhois.lookup_info(ip) + m.reply reply + end + + def userip(m, params) + #users = @channels[m.channel].users + #m.reply "users = #{users.inspect}" + #m.reply @bot.sendq("WHO #{params[:user]}") + end + +end + +plugin = IPLookupPlugin.new +plugin.map 'iplookup :ip', :action => 'iplookup', :requirements => {:ip => /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/} +plugin.map 'iplookup :domain', :action => 'iplookup', :requirements => {:domain => /^[a-z0-9\.\-]{4,255}$/i} +plugin.map 'userip :user', :action => 'userip', :requirements => {:user => /\w+/} + + +if __FILE__ == $0 + include ArinWhois + data = open('whoiscgm.txt').read + c = ArinWhoisParser.new data + puts c.get_parsed_data.inspect +end \ No newline at end of file -- cgit v1.2.3