From 4c9408181e395b7dcb7fd95a991b9073088f662c Mon Sep 17 00:00:00 2001 From: David Gadling Date: Tue, 2 Feb 2010 17:02:16 -0800 Subject: [PATCH] geoip: Add blogama and allow for fallback options --- data/rbot/plugins/geoip.rb | 111 +++++++++++++++++++++++++++---------- 1 file changed, 82 insertions(+), 29 deletions(-) diff --git a/data/rbot/plugins/geoip.rb b/data/rbot/plugins/geoip.rb index 61551172..3b7bf751 100755 --- a/data/rbot/plugins/geoip.rb +++ b/data/rbot/plugins/geoip.rb @@ -11,40 +11,78 @@ module ::GeoIP class InvalidHostError < RuntimeError; end + class BadAPIError < RuntimeError; end - GEO_IP_PRIMARY = "http://lakka.kapsi.fi:40086/lookup.yaml?host=" - GEO_IP_SECONDARY = "http://www.geoiptool.com/en/?IP=" HOST_NAME_REGEX = /^[a-z0-9\-]+(?:\.[a-z0-9\-]+)*\.[a-z]{2,4}/i - REGEX = { - :country => %r{Country:.*? (.*?)}m, - :region => %r{Region:.*?(.*?)}m, - :city => %r{City:.*?(.*?)}m, - :lat => %r{Latitude:.*?(.*?)}m, - :lon => %r{Longitude:.*?(.*?)}m - } - def self.valid_host?(hostname) hostname =~ HOST_NAME_REGEX || hostname =~ Resolv::IPv4::Regex && (hostname.split(".").map { |e| e.to_i }.max <= 255) end - def self.resolve(hostname) - raise InvalidHostError unless valid_host?(hostname) + def self.geoiptool(ip) + url = "http://www.geoiptool.com/en/?IP=" + regexes = { + :country => %r{Country:.*? (.*?)}m, + :region => %r{Region:.*?(.*?)}m, + :city => %r{City:.*?(.*?)}m, + :lat => %r{Latitude:.*?(.*?)}m, + :lon => %r{Longitude:.*?(.*?)}m + } + res = {} + raw = Irc::Utils.bot.httputil.get_response(url+ip) + raw = raw.decompress_body(raw.raw_body) + + regexes.each { |key, regex| res[key] = Iconv.conv('utf-8', 'ISO-8859-1', raw.scan(regex).to_s) } + + return res + end - yaml = Irc::Utils.bot.httputil.get(GEO_IP_PRIMARY+hostname) + def self.kapsi(ip) + url = "http://lakka.kapsi.fi:40086/lookup.yaml?host=" + yaml = Irc::Utils.bot.httputil.get(url+ip) + return YAML::load(yaml) + end - if yaml - return YAML::load(yaml) + def self.blogama(ip) + url = "http://ipinfodb.com/ip_query.php?ip=" + debug "Requesting #{url+ip}" + + xml = Irc::Utils.bot.httputil.get(url+ip) + + if xml + obj = REXML::Document.new(xml) + debug "Found #{obj}" + newobj = { + :country => obj.elements["Response"].elements["CountryName"].text, + :city => obj.elements["Response"].elements["City"].text, + :region => obj.elements["Response"].elements["RegionName"].text, + } + debug "Returning #{newobj}" + return newobj else - res = {} - raw = Irc::Utils.bot.httputil.get_response(GEO_IP_SECONDARY+hostname) - raw = raw.decompress_body(raw.raw_body) + raise InvalidHostError + end + end - REGEX.each { |key, regex| res[key] = Iconv.conv('utf-8', 'ISO-8859-1', raw.scan(regex).to_s) } + def self.resolve(hostname, api) + raise InvalidHostError unless valid_host?(hostname) - return res + begin + ip = Resolv.getaddress(hostname) + rescue Resolv::ResolvError + raise InvalidHostError end + + jump_table = { + "blogama" => Proc.new { |ip| blogama(ip) }, + "kapsi" => Proc.new { |ip| kapsi(ip) }, + "geoiptool" => Proc.new { |ip| geoiptool(ip) }, + } + + raise BadAPIError unless jump_table.key?(api) + + return jump_table[api].call(ip) end end @@ -68,6 +106,10 @@ class Stack end class GeoIpPlugin < Plugin + Config.register Config::ArrayValue.new('geoip.sources', + :default => [ "blogama", "kapsi", "geoiptool" ], + :desc => "Which API to use for lookups. Supported values: blogama, kapsi, geoiptool") + def help(plugin, topic="") "geoip [] => returns the geographic location of whichever has been given -- note: user can be anyone on the network" end @@ -130,12 +172,23 @@ class GeoIpPlugin < Plugin def host2output(host, nick=nil) return "127.0.0.1 could not be res.. wait, what?" if host == "127.0.0.1" + geo = {:country => ""} begin - geo = GeoIP::resolve(host) - - raise if geo[:country].empty? + apis = @bot.config['geoip.sources'] + apis.compact.each { |api| + geo = GeoIP::resolve(host, api) + if geo[:country] != "" + break + end + } rescue GeoIP::InvalidHostError, RuntimeError - return _("#{nick ? "#{nick}'s location" : host} could not be resolved") + if nick + return _("#{nick}'s location could not be resolved") + else + return _("#{host} could not be resolved") + end + rescue GeoIP::BadAPIError + return _("The owner configured me to use an API that doesn't exist, bug them!") end res = _("%{thing} is #{nick ? "from" : "located in"}") % { @@ -143,18 +196,18 @@ class GeoIpPlugin < Plugin :country => geo[:country] } - res << " %{city}," % { + res << " %{city}" % { :city => geo[:city] } unless geo[:city].to_s.empty? + res << " %{region}," % { + :region => geo[:region] + } unless geo[:region].to_s.empty? || geo[:region] == geo[:city] + res << " %{country}" % { :country => geo[:country] } - res << " (%{region})" % { - :region => geo[:region] - } unless geo[:region].to_s.empty? || geo[:region] == geo[:city] - return res end end -- 2.39.2