Class: GeoIP
- Inherits:
-
Object
- Object
- GeoIP
- Defined in:
- lib/geoip.rb
Constant Summary collapse
- VERSION =
"0.8.7"
Instance Attribute Summary collapse
-
#databaseType ⇒ Object
readonly
Returns the value of attribute databaseType.
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.
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)
664 665 666 667 668 669 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 |
# File 'lib/geoip.rb', line 664 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) == "\xFF\xFF\xFF" @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)
Returns the value of attribute databaseType.
658 659 660 |
# File 'lib/geoip.rb', line 658 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
916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 |
# File 'lib/geoip.rb', line 916 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] 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 twelve or fourteen 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
-
The ISO3166-1 two-character country code
-
The ISO3166-2 three-character country code
-
The ISO3166 English-language name of the country
-
The two-character continent code
-
The region name
-
The city name
-
The postal code
-
The latitude
-
The longitude
-
The USA dma_code and area_code, if available (REV1 City database)
857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 |
# File 'lib/geoip.rb', line 857 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) 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. 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
-
The ISO3166-1 two-character country code
-
The ISO3166-2 three-character country code
-
The ISO3166 English-language name of the country
-
The two-character continent code
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 |
# File 'lib/geoip.rb', line 722 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 code CountryCode3[code], # ISO3166-2 code CountryName[code], # Country name, per IS03166 CountryContinent[code] ] # Continent code. end |
#each ⇒ Object
Iterate through a GeoIP city database
948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 |
# File 'lib/geoip.rb', line 948 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
hostname
is a String holding the host’s DNS name or numeric IP address. Return the ISP name
888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 |
# File 'lib/geoip.rb', line 888 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 |