1 #################################################################
\r
3 # ----------------------------
\r
4 # by Chris Gahan (chris@ill-logic.com)
\r
8 # Lets you lookup the owner and their address for any IP address
\r
11 #################################################################
\r
16 #################################################################
\r
17 ## ARIN Whois module...
\r
24 keys.grep(/^(City|Address|StateProv|(Org|Cust)Name)$/).any?
\r
28 keys.grep(/^(CIDR|NetHandle|Parent)$/).any?
\r
32 keys.grep(/^(R|Org)(Tech|Abuse)(Handle|Name|Phone|Email)$/).any?
\r
36 customer? or network? or contact?
\r
40 self[keys.grep(/^(Org|Cust)Name$/).first]
\r
44 [ self['City'], self['StateProv'], self['Country'] ].compact.join(', ')
\r
48 [ self['Address'], location, self['PostalCode'] ].compact.join(', ')
\r
53 class ArinWhoisParser
\r
55 def initialize(data)
\r
59 def split_array_at(a, &block)
\r
60 return a unless a.any?
\r
66 a.each_with_index do |el,i|
\r
69 results << a[last_cutpoint...i]
\r
75 if last_cutpoint < a.size or last_cutpoint == 0
\r
76 results << a[last_cutpoint..-1]
\r
82 # Whois output format
\r
83 # ------------------------
\r
92 # Network Information:
\r
93 # CIDR (69.195.25.0/25)
\r
94 # NetHandle (NET-72-14-192-0-1)
\r
95 # Parent (NET-72-0-0-0-0)
\r
98 # ({R,Org}{Tech,Abuse}{Handle,Name,Phone,Email})*
\r
101 return if @data =~ /^No match found /
\r
102 chunks = @data.gsub(/^# ARIN WHOIS database, last updated.+/m, '').scan(/(([^\n]+\n)+\n)/m)
\r
103 chunks.map do |chunk|
\r
106 chunk[0].scan(/([A-Za-z]+?):(.*)/).each do |tuple|
\r
108 result[tuple[0]] = tuple[1].empty? ? nil : tuple[1]
\r
116 def get_parsed_data
\r
117 return unless chunks = parse_chunks
\r
119 results = split_array_at(parse_chunks) {|chunk|chunk.customer?}
\r
120 results.map do |chunks|
\r
122 :customer => chunks.select{|x|x.customer?}[0],
\r
123 :net => chunks.select{|x|x.network?}[0],
\r
124 :contacts => chunks.select{|x|x.contact?}
\r
129 # Return a hash with :customer, :net, and :contacts info filled in.
\r
130 def get_most_specific_owner
\r
131 return unless datas = get_parsed_data
\r
133 datas_with_bitmasks = datas.map do |data|
\r
134 bitmask = data[:net]['CIDR'].split('/')[1].to_i
\r
137 #datas_with_bitmasks.sort.each{|x|puts x[0]}
\r
138 winner = datas_with_bitmasks.sort[-1][1]
\r
141 end # of class ArinWhoisParser
\r
145 def raw_whois(query_string, host)
\r
146 s = TCPsocket.open(host, 43)
\r
147 s.write(query_string+"\n")
\r
154 data = raw_whois("+#{ip}", 'whois.arin.net')
\r
155 arin = ArinWhoisParser.new data
\r
156 arin.get_most_specific_owner
\r
159 def lookup_location(ip)
\r
160 result = lookup(ip)
\r
161 result[:customer].location
\r
164 def lookup_address(ip)
\r
165 result = lookup(ip)
\r
166 result[:customer].address
\r
169 def lookup_info(ip)
\r
170 if result = lookup(ip)
\r
171 "#{result[:net]['CIDR']} => #{result[:customer].owner} (#{result[:customer].address})"
\r
173 "Address not found."
\r
181 #################################################################
\r
185 class IPLookupPlugin < Plugin
\r
186 def help(plugin, topic="")
187 "iplookup [ip address / domain name] => lookup info about the owner of the IP address from the ARIN whois database"
190 def iplookup(m, params)
\r
194 ip = Resolv.getaddress(params[:domain])
\r
195 reply += "#{params[:domain]} | "
\r
197 m.reply "#{e.message}"
\r
204 reply += ArinWhois.lookup_info(ip)
\r
208 def userip(m, params)
\r
209 #users = @channels[m.channel].users
\r
210 #m.reply "users = #{users.inspect}"
\r
211 #m.reply @bot.sendq("WHO #{params[:user]}")
\r
216 plugin = IPLookupPlugin.new
217 plugin.map 'iplookup :ip', :action => 'iplookup', :requirements => {:ip => /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/}
\r
218 plugin.map 'iplookup :domain', :action => 'iplookup', :requirements => {:domain => /^[a-z0-9\.\-]{4,255}$/i}
\r
219 plugin.map 'userip :user', :action => 'userip', :requirements => {:user => /\w+/}
224 data = open('whoistest.txt').read
\r
225 c = ArinWhoisParser.new data
\r
226 puts c.get_parsed_data.inspect
\r