1 #################################################################
3 # ----------------------------
4 # by Chris Gahan (chris@ill-logic.com)
8 # Lets you lookup the owner and their address for any IP address
11 #################################################################
16 #################################################################
17 ## ARIN Whois module...
24 keys.grep(/^(City|Address|StateProv|(Org|Cust)Name)$/).any?
28 keys.grep(/^(CIDR|NetHandle|Parent)$/).any?
32 keys.grep(/^(R|Org)(Tech|Abuse)(Handle|Name|Phone|Email)$/).any?
36 customer? or network? or contact?
40 self[keys.grep(/^(Org|Cust)Name$/).first]
44 [ self['City'], self['StateProv'], self['Country'] ].compact.join(', ')
48 [ self['Address'], location, self['PostalCode'] ].compact.join(', ')
59 def split_array_at(a, &block)
60 return a unless a.any?
66 a.each_with_index do |el,i|
69 results << a[last_cutpoint...i]
75 if last_cutpoint < a.size or last_cutpoint == 0
76 results << a[last_cutpoint..-1]
83 # ------------------------
92 # Network Information:
93 # CIDR (69.195.25.0/25)
94 # NetHandle (NET-72-14-192-0-1)
95 # Parent (NET-72-0-0-0-0)
98 # ({R,Org}{Tech,Abuse}{Handle,Name,Phone,Email})*
101 return if @data =~ /^No match found /
102 chunks = @data.gsub(/^# ARIN WHOIS database, last updated.+/m, '').scan(/(([^\n]+\n)+\n)/m)
103 chunks = chunks.map do |chunk|
106 chunk[0].scan(/([A-Za-z]+?):(.*)/).each do |tuple|
108 result[tuple[0]] = tuple[1].empty? ? nil : tuple[1]
113 chunks.reject(&:empty?)
118 return unless chunks = parse_chunks
120 results = split_array_at(chunks) {|chunk|chunk.customer?}
121 results.map do |data|
123 :customer => data.select{|x|x.customer?}[0],
124 :net => data.select{|x|x.network?}[0],
125 :contacts => data.select{|x|x.contact?}
130 # Return a hash with :customer, :net, and :contacts info filled in.
131 def get_most_specific_owner
132 return unless datas = get_parsed_data
134 datas_with_bitmasks = datas.map do |data|
135 next unless data[:customer]
136 next unless net_data = data[:net]
137 bitmask = net_data['CIDR'].split('/')[1].to_i
140 datas_with_bitmasks.compact!
141 #datas_with_bitmasks.sort.each{|x|puts x[0]}
142 winner = datas_with_bitmasks.sort[-1][1]
145 end # of class ArinWhoisParser
149 def raw_whois(query_string, host)
150 s = TCPSocket.open(host, 43)
151 s.write(query_string+"\n")
158 data = raw_whois("+ n #{ip}", 'whois.arin.net')
159 arin = ArinWhoisParser.new data
160 arin.get_most_specific_owner
163 def lookup_location(ip)
165 result[:customer].location
168 def lookup_address(ip)
170 result[:customer].address
174 if result = lookup(ip)
175 "#{result[:net]['CIDR']} => #{result[:customer].owner} (#{result[:customer].address})"
185 #################################################################
189 class IPLookupPlugin < Plugin
190 def help(plugin, topic="")
191 "iplookup [ip address / domain name] => lookup info about the owner of the IP address from the ARIN whois database"
194 def iplookup(m, params)
196 if params[:domain].match(/^#{Regexp::Irc::HOSTADDR}$/)
200 ip = Resolv.getaddress(params[:domain])
201 reply << "#{params[:domain]} | "
203 m.reply "#{e.message}"
208 reply << ArinWhois.lookup_info(ip)
213 def userip(m, params)
214 m.reply "not implemented yet"
215 #users = @channels[m.channel].users
216 #m.reply "users = #{users.inspect}"
217 #m.reply @bot.sendq("WHO #{params[:user]}")
222 plugin = IPLookupPlugin.new
223 plugin.map 'iplookup :domain', :action => 'iplookup', :thread => true
224 plugin.map 'userip :user', :action => 'userip', :requirements => {:user => /\w+/}, :thread => true
229 data = open('whoistest.txt').read
230 c = ArinWhoisParser.new data
231 puts c.get_parsed_data.inspect