55 lines
1.4 KiB
Crystal
55 lines
1.4 KiB
Crystal
require "maxminddb"
|
|
|
|
class IpLookup
|
|
@@instance : MaxMindDB::Reader? = nil
|
|
|
|
record Country, code : String? = nil, name : String? = nil
|
|
|
|
getter ip : String
|
|
getter country : Country?
|
|
|
|
def self.load_mmdb(mmdb_file_path : String)
|
|
@@instance = MaxMindDB.open(mmdb_file_path)
|
|
end
|
|
|
|
def initialize(ip_address : String)
|
|
@ip = ip_address
|
|
@country = nil
|
|
|
|
return if @@instance.nil? || ip_address == "Unknown" || ip_address.empty?
|
|
|
|
begin
|
|
lookup = @@instance.not_nil!.get(ip_address)
|
|
|
|
country_code = lookup["country"]?.try &.["iso_code"]?.try &.as_s
|
|
country_name = lookup["country"]?.try &.["names"]?.try &.["en"]?.try &.as_s
|
|
|
|
if country_code || country_name
|
|
@country = Country.new(
|
|
code: country_code,
|
|
name: country_name
|
|
)
|
|
end
|
|
rescue ex
|
|
# Silently handle lookup errors
|
|
Log.error { "IP lookup failed: #{ex.message}" }
|
|
end
|
|
end
|
|
|
|
def self.extract_ip(address_string : String?) : String?
|
|
return nil if address_string.nil?
|
|
|
|
if address_string.includes?('[') # IPv6 with port: [2001:db8::1]:8080
|
|
address_string.split(']').first.sub('[', '\'')
|
|
elsif address_string.includes?(':')
|
|
if address_string.count(':') > 1 # IPv6 without port
|
|
address_string
|
|
else # IPv4 with port: 192.168.1.1:8080
|
|
address_string.split(':').first
|
|
end
|
|
else # Address without port
|
|
address_string
|
|
end
|
|
end
|
|
end
|