Class: GeoIP
- Inherits:
-
Object
- Object
- GeoIP
- Defined in:
- lib/geoip.rb
Defined Under Namespace
Modules: ASNAccessors, CityAccessors, CountryAccessors
Constant Summary collapse
- VERSION =
The GeoIP GEM version number
"1.0.0"
- GEOIP_COUNTRY_EDITION =
1
- GEOIP_CITY_EDITION_REV1 =
2
- GEOIP_REGION_EDITION_REV1 =
3
- GEOIP_ISP_EDITION =
4
- GEOIP_ORG_EDITION =
5
- GEOIP_CITY_EDITION_REV0 =
6
- GEOIP_REGION_EDITION_REV0 =
7
- GEOIP_PROXY_EDITION =
8
- GEOIP_ASNUM_EDITION =
9
- GEOIP_NETSPEED_EDITION =
10
Instance Attribute Summary collapse
-
#databaseType ⇒ Object
readonly
The Edition number that identifies which kind of database you’ve opened.
Instance Method Summary collapse
-
#asn(hostname) ⇒ Object
Search a ASN GeoIP database for the specified host, returning the AS number + description.
-
#city(hostname) ⇒ Object
Search the GeoIP database for the specified host, returning city info.
-
#country(hostname) ⇒ Object
Search the GeoIP database for the specified host, returning country info.
-
#each ⇒ Object
Iterate through a GeoIP city database.
-
#initialize(filename, flags = 0) ⇒ GeoIP
constructor
Open the GeoIP database and determine the file format version.
-
#isp(hostname) ⇒ Object
(also: #organization)
Search a ISP GeoIP database for the specified host, returning the ISP Not all GeoIP databases contain ISP information.
Constructor Details
#initialize(filename, flags = 0) ⇒ GeoIP
Open the GeoIP database and determine the file format version
filename
is a String holding the path to the GeoIP.dat file options
is an integer holding caching flags (unimplemented)
670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 |
# File 'lib/geoip.rb', line 670 def initialize(filename, flags = 0) @mutex = IO.respond_to?(:pread) ? false : Mutex.new @flags = flags @databaseType = GEOIP_COUNTRY_EDITION @record_length = STANDARD_RECORD_LENGTH @file = File.open(filename, 'rb') @file.seek(-3, IO::SEEK_END) 0.upto(STRUCTURE_INFO_MAX_SIZE-1) { |i| if @file.read(3).bytes.all?{|byte| 255 == byte} @databaseType = @file.respond_to?(:getbyte) ? @file.getbyte : @file.getc @databaseType -= 105 if @databaseType >= 106 if (@databaseType == GEOIP_REGION_EDITION_REV0) # Region Edition, pre June 2003 @databaseSegments = [ STATE_BEGIN_REV0 ] elsif (@databaseType == GEOIP_REGION_EDITION_REV1) # Region Edition, post June 2003 @databaseSegments = [ STATE_BEGIN_REV1 ] elsif (@databaseType == GEOIP_CITY_EDITION_REV0 || @databaseType == GEOIP_CITY_EDITION_REV1 || @databaseType == GEOIP_ORG_EDITION || @databaseType == GEOIP_ISP_EDITION || @databaseType == GEOIP_ASNUM_EDITION) # City/Org Editions have two segments, read offset of second segment @databaseSegments = [ 0 ] sr = @file.read(3).unpack("C*") @databaseSegments[0] += le_to_ui(sr) if (@databaseType == GEOIP_ORG_EDITION || @databaseType == GEOIP_ISP_EDITION) @record_length = 4 end end break else @file.seek(-4, IO::SEEK_CUR) end } if (@databaseType == GEOIP_COUNTRY_EDITION || @databaseType == GEOIP_PROXY_EDITION || @databaseType == GEOIP_NETSPEED_EDITION) @databaseSegments = [ COUNTRY_BEGIN ] end end |
Instance Attribute Details
#databaseType ⇒ Object (readonly)
The Edition number that identifies which kind of database you’ve opened
664 665 666 |
# File 'lib/geoip.rb', line 664 def databaseType @databaseType end |
Instance Method Details
#asn(hostname) ⇒ Object
Search a ASN GeoIP database for the specified host, returning the AS number + description
hostname
is a String holding the host’s DNS name or numeric IP address. Return the AS number + description
Source: geolite.maxmind.com/download/geoip/database/asnum/GeoIPASNum.dat.gz
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 |
# File 'lib/geoip.rb', line 848 def asn(hostname) ip = hostname if ip.kind_of?(String) && ip !~ /^[0-9.]*$/ # Lookup IP address, we were given a name ip = IPSocket.getaddress(hostname) ip = '0.0.0.0' if ip == '::1' end # Convert numeric IP address to an integer ipnum = iptonum(ip) if (@databaseType != GEOIP_ASNUM_EDITION) throw "Invalid GeoIP database type, can't look up ASN by IP" end pos = seek_record(ipnum); off = pos + (2*@record_length-1) * @databaseSegments[0] record = atomic_read(MAX_ASN_RECORD_LENGTH, off) record = record.sub(/\000.*/n, '') if record =~ /^(AS\d+)\s(.*)$/ # AS####, Description return [$1, $2].extend(ASNAccessors) end end |
#city(hostname) ⇒ Object
Search the GeoIP database for the specified host, returning city info.
hostname
is a String holding the host’s DNS name or numeric IP address. Return an array of fourteen elements:
-
The host or IP address string as requested
-
The IP address string after looking up the host
-
The two-character country code (ISO 3166-1 alpha-2)
-
The three-character country code (ISO 3166-2 alpha-3)
-
The ISO 3166 English-language name of the country
-
The two-character continent code
-
The region name (state or territory)
-
The city name
-
The postal code (zipcode)
-
The latitude
-
The longitude
-
The USA dma_code if known (only REV1 City database)
-
The USA area_code if known (only REV1 City database)
-
The timezone name, if known
The array has been extended with methods listed in GeoIP::CityAccessors.ACCESSORS: request, ip, country_code2, country_code3, country_name, continent_code, region_name, city_name, postal_code, latitude, longitude, dma_code, area_code, timezone. In addition, to_hash
provides a symbol-keyed hash for the above values.
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 |
# File 'lib/geoip.rb', line 788 def city(hostname) ip = hostname if ip.kind_of?(String) && ip !~ /^[0-9.]*$/ # Lookup IP address, we were given a name ip = IPSocket.getaddress(hostname) ip = '0.0.0.0' if ip == '::1' end # Convert numeric IP address to an integer ipnum = iptonum(ip) if (@databaseType != GEOIP_CITY_EDITION_REV0 && @databaseType != GEOIP_CITY_EDITION_REV1) throw "Invalid GeoIP database type, can't look up City by IP" end pos = seek_record(ipnum); # This next statement was added to MaxMind's C version after it was rewritten in Ruby. # It prevents unassigned IP addresses from returning bogus data. There was concern over # whether the changes to an application's behaviour were always correct, but this has been # tested using an exhaustive search of the top 16 bits of the IP address space. The records # where the change takes effect contained *no* valid data. If you're concerned, email me, # and I'll send you the test program so you can test whatever IP range you think is causing # problems, as I don't care to undertake an exhaustive search of the 32-bit space. return nil if pos == @databaseSegments[0] read_city(pos, hostname, ip).extend(CityAccessors) end |
#country(hostname) ⇒ Object
Search the GeoIP database for the specified host, returning country info
hostname
is a String holding the host’s DNS name or numeric IP address. If the database is a City database (normal), return the result that city
would return. Otherwise, return an array of seven elements:
-
The host or IP address string as requested
-
The IP address string after looking up the host
-
The GeoIP country-ID as an integer (N.B. this is excluded from the city results!)
-
The two-character country code (ISO 3166-1 alpha-2)
-
The three-character country code (ISO 3166-2 alpha-3)
-
The ISO 3166 English-language name of the country
-
The two-character continent code
The array has been extended with methods listed in GeoIP::CountryAccessors.ACCESSORS: request, ip, country_code, country_code2, country_code3, country_name, continent_code. In addition, to_hash
provides a symbol-keyed hash for the above values.
733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 |
# File 'lib/geoip.rb', line 733 def country(hostname) if (@databaseType == GEOIP_CITY_EDITION_REV0 || @databaseType == GEOIP_CITY_EDITION_REV1) return city(hostname) end ip = hostname if ip.kind_of?(String) && ip !~ /^[0-9.]*$/ # Lookup IP address, we were given a name ip = IPSocket.getaddress(hostname) ip = '0.0.0.0' if ip == '::1' end # Convert numeric IP address to an integer ipnum = iptonum(ip) if (@databaseType != GEOIP_COUNTRY_EDITION && @databaseType != GEOIP_PROXY_EDITION && @databaseType != GEOIP_NETSPEED_EDITION) throw "Invalid GeoIP database type, can't look up Country by IP" end code = seek_record(ipnum) - COUNTRY_BEGIN; [ hostname, # Requested hostname ip, # Ip address as dotted quad code, # GeoIP's country code CountryCode[code], # ISO3166-1 alpha-2 code CountryCode3[code], # ISO3166-2 alpha-3 code CountryName[code], # Country name, per ISO 3166 CountryContinent[code] # Continent code. ].extend(CountryAccessors) end |
#each ⇒ Object
Iterate through a GeoIP city database
880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 |
# File 'lib/geoip.rb', line 880 def each if (@databaseType != GEOIP_CITY_EDITION_REV0 && @databaseType != GEOIP_CITY_EDITION_REV1) throw "Invalid GeoIP database type, can't iterate thru non-City database" end @iter_pos = @databaseSegments[0] + 1 num = 0 until((rec = read_city(@iter_pos)).nil?) yield(rec) print "#{num}: #{@iter_pos}\n" if((num += 1) % 1000 == 0) end @iter_pos = nil self end |
#isp(hostname) ⇒ Object Also known as: organization
Search a ISP GeoIP database for the specified host, returning the ISP Not all GeoIP databases contain ISP information. Check maxmind.com
hostname
is a String holding the host’s DNS name or numeric IP address. Return the ISP name
820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 |
# File 'lib/geoip.rb', line 820 def isp(hostname) ip = hostname if ip.kind_of?(String) && ip !~ /^[0-9.]*$/ # Lookup IP address, we were given a name ip = IPSocket.getaddress(hostname) ip = '0.0.0.0' if ip == '::1' end # Convert numeric IP address to an integer ipnum = iptonum(ip) if @databaseType != GEOIP_ISP_EDITION throw "Invalid GeoIP database type, can't look up Organization/ISP by IP" end pos = seek_record(ipnum); off = pos + (2*@record_length-1) * @databaseSegments[0] record = atomic_read(MAX_ORG_RECORD_LENGTH, off) record = record.sub(/\000.*/n, '') record end |