summaryrefslogtreecommitdiff
path: root/data/rbot/plugins
diff options
context:
space:
mode:
authorChris Gahan <chris@ill-logic.com>2006-03-25 12:12:36 +0000
committerChris Gahan <chris@ill-logic.com>2006-03-25 12:12:36 +0000
commite101e9aaed7e1a7f8acdac870fc237275ae30bd2 (patch)
treef39a7e2c5d667015a0d727f0825b12e521fe466e /data/rbot/plugins
parentee3677e075a6881425e66b29d566d3a4f53a564d (diff)
New plugin that finds out where an IP or domain is located (by looking up the IP address' owner in the ARIN whois database)
Diffstat (limited to 'data/rbot/plugins')
-rw-r--r--data/rbot/plugins/iplookup.rb222
1 files changed, 222 insertions, 0 deletions
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