# This gem module provides a classes to find the right Regional Internet Registry # for a given IP Address. The query method will navigate each major RIR until a # response is found. # # Author:: Al Kivi <al.kivi@vizitrax.com> # License:: MIT module Vizi # This class includes a set of methods to navigate and query the regional whois servers class Gowhois # This method will navigate each whois server until a response is found def query (ipaddr) s = "arin" response = ruby_whois(ipaddr, s) if response.index("(NET") # look for dual NET blocks in ARIN responses t1 = response netaddrs = response.scan(/\(NET-\w+\-\w+\-\w+\-\w+\-\w+\)/) netaddr = netaddrs[netaddrs.length-1].scan(/NET-\w+\-\w+\-\w+\-\w+\-\w+/) response = ruby_whois(netaddr[0], s) end if response.index("whois.ripe.net") s = "ripe" response = ruby_whois(ipaddr, s) elsif response.index("whois.apnic.net") s = "apnic" response = ruby_whois(ipaddr, s) elsif response.index("whois.lacnic.net") s = "lacnic" response = ruby_whois(ipaddr, s) if response.length > 4000 # parse very long responses lines = response.split(/\r\n/) lines.delete_if { |e| e =~ /nserver:/ } lines.delete_if { |e| e =~ /nsstat:/ } lines.delete_if { |e| e =~ /nslastaa:/ } lines.delete_if { |e| e =~ /inetrev:/ } response="" i=0 while i<lines.length response = response+lines[i]+"\r\n" i = i+1 end end elsif response.index("afrinic.net") s = "afrinic" response = ruby_whois(ipaddr, s) elsif response.length >250 and response.length < 500 str = response[100..250] x = str.index("(") y = str.index(")") if x != nil and y != nil net = str[x+1..y-1] response = ruby_whois(net, s) end end ccode = get_country(response) return response, ccode, s end # This method will parse the response to find the two character country code def get_country (response) temp = response.upcase temp.delete!("\t") temp.delete!(" ") x = temp.index("COUNTRY:") ccode = nil if x != nil ccode = temp[x+8..x+9] elsif temp.index(".BR") ccode = "BR" else ccode ="?" end return ccode end # This method the ruby version of the whois command function def ruby_whois (send_string, host) # p send_string + " .. " + host if host.index(".") == nil host = "whois."+host+".net" end add_string = "" add_string = "n " if host == "whois.arin.net" add_string = "n ! " if send_string.index("NET") == 0 s = TCPSocket.open(host,43) s.write(add_string+send_string+"\n") ret = "" while s.gets do ret += $_ end s.close return ret rescue # rescue logic if not found ret="Not found" return ret end end # This class will parse the response string from a Whois server class Formatter def initialize @cities = YAML.load_file("config/cities.yml") end # This method will parse response string # def parse (contents, country, server) def parse (contents, country) name_list = ["COUNTRY","NETNAME","ORGNAME","ORG-NAME","CUSTNAME","OWNER","ADDRESS","DESCR","CITY","STATEPROV","POSTALCODE"] country_list = ["GERMANY","UNITED KINGDOM","UK","ENGLAND","INDIA","NETHERLANDS","SPAIN","BELGIUM","PR CHINA","NORWAY"] odd_words = ["ABUSE", "PHISH", "SPAM", "ACTIVITY","PROVINCE NETWORK","COMMUNICATION DIVISION","IMPROPER","SERVICE PROVIDER","IP POOL","-----","*****","#####","IP ASSIGNMENT","FOR CUSTOMER","THIS SPACE"] trim_orgname = ["LIMITED", "LTD", "INC", "CORPORATION", "LLC", "HOLDINGS", "UNICATIONS", "INFORMATION CENTER"] # formatted_file = File.open('./log/formatted.log', 'a') a = contents.upcase.split(/\n/) i = -1 line = [nil,nil] lastname = nil orgname = nil cityflag = false addressflag = false country_count = 0 da_count = 0 netname_count = 0 darray = [] outstring = "" while i < a.length-1 i = i + 1 line = [nil, nil] goodline = true current = a[i].chomp if current.length < 2 goodline = false else goodline = false if current[0] == "%" or current[0] == "#" end if goodline line = current.split(":") line_name = line[0] line_value = line[1] line_value = line_value.strip if not line_value.nil? if line_value.nil? line_value = "" if lastname == "ADDRESS" and line_name != line_name.lstrip line_name = lastname end else addressflag = true if line_name == "ADDRESS" end odd_words.each {|w| goodline = false if line_value.index(w) } if line_name == "COUNTRY" country_count = country_count + 1 line_value = line_value[0..1] if not line_value.nil? end if line_name == "NETNAME" netname_count = netname_count + 1 netname = line_value if netname_count == 1 end if not ["NETNAME","POSTALCODE"].index(line_name) line_value = line_value.lstrip.gsub(",",";") line_value = line_value.lstrip.gsub(".","") line_value = line_value.lstrip.gsub("; ",";") line_value = line_value.lstrip.gsub(" ;",";") line_value = line_value.lstrip.gsub("/",";") # line_value = line_value.lstrip.gsub("-",";") line_value = line_value.chomp(";") end if ["ORGNAME","CUSTNAME","OWNER","ORG-NAME"].index(line_name) orgname = (line_value + ";").split(";")[0] end if line_name == "DESCR" or line_name == "ADDRESS" goodline = false if line_value.length == 0 goodline = false if da_count > 6 goodline = false if darray.index(line_value) if goodline darray << line_value da_count = da_count + 1 end end goodline = false if country_count > 1 and line_name == "COUNTRY" goodline = false if netname_count > 1 and line_name == "NETNAME" goodline = false if line_value[0] == "-" goodline = false if country_list.index(line_value) goodline = false if line_name == "ADDRESS" and line_value == country goodline = false if addressflag and line_name == "DESCR" goodline = false if line_value.length < 2 cityflag = true if line_name == "CITY" and line_value.length > 0 else line_name = current line_value = "" end lastname = line_name if goodline if name_list.index(line_name) newline = line_name + ': ' + line_value + '\n' outstring = outstring + newline end end end # At the end of regular parse, find organization NAME if needed if orgname.nil? if darray[0].nil? orgname = 'NOT FOUND' else orgname = (darray[0] + ";").split(";")[0] end end if country != "CA" and country != "US" and not orgname[/[0123456789]/].nil? orgname = netname if not netname.nil? end trim_orgname.each {|p| orgname = orgname.sub(p, "") } orgname = orgname.sub(".","") orgname = orgname[0..29] orgname = orgname[0..28-orgname.reverse.index(" ")] if not orgname.reverse.index(" ").nil? newline = 'NAME: ' + orgname + '\n' outstring = outstring + newline # Search for city name, if not identified if country != "CA" and country != "US" if not cityflag candidates = @cities["."+country] city = "UNKNOWN" if not darray[0].nil? and not candidates.nil? darray.each {|line| candidates.each {|c| city = c.delete("!") if c.class != Hash and line.index(c.delete("!")) break if city != 'UNKNOWN' } } end if city == "UNKNOWN" and not candidates.nil? candidates.each {|c| if c.class == String city = c.delete("!") if c.index("!") break if city != 'UNKNOWN' end } end newline = 'CITY: ' + city + '\n' outstring = outstring + newline end end return outstring end def createhash(formatted) farray = formatted.split('\n') hashout = Hash.new farray.each {|x| line = x.split(': ') hashout[line[0]] = line[1] } hashout['NAME'] = '??' if hashout['NAME'].nil? hashout['CITY'] = '??' if hashout['CITY'].nil? hashout['COUNTRY'] = '??' if hashout['COUNTRY'].nil? hashout end end end