diff options
author | Chris Gahan <chris@ill-logic.com> | 2006-03-25 12:12:36 +0000 |
---|---|---|
committer | Chris Gahan <chris@ill-logic.com> | 2006-03-25 12:12:36 +0000 |
commit | e101e9aaed7e1a7f8acdac870fc237275ae30bd2 (patch) | |
tree | f39a7e2c5d667015a0d727f0825b12e521fe466e /data/rbot/plugins | |
parent | ee3677e075a6881425e66b29d566d3a4f53a564d (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.rb | 222 |
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 |