geoip 0.8.9 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +18 -6
- data/lib/geoip.rb +203 -146
- metadata +4 -4
data/README.rdoc
CHANGED
@@ -16,19 +16,31 @@ This release adds support for timezone names, thanks to Tonni Aagesen.
|
|
16
16
|
== SYNOPSIS:
|
17
17
|
|
18
18
|
require 'geoip'
|
19
|
-
|
20
|
-
|
19
|
+
|
20
|
+
# Use the country database:
|
21
|
+
GeoIP.new('GeoIP.dat').country('www.atlantis.sk')
|
22
|
+
=> ["www.atlantis.sk", "217.67.18.26", 196, "SK", "SVK", "Slovakia", "EU"]
|
21
23
|
|
22
24
|
Returned values are the requested hostname, the IP address as a dotted quad,
|
23
|
-
Maxmind's country code, the ISO3166-1 country code, the ISO3166-2
|
24
|
-
the ISO3166 country name, and the continent code.
|
25
|
+
Maxmind's country code, the ISO3166-1 alpha-2 country code, the ISO3166-2 alpha-3
|
26
|
+
country code, the ISO3166 country name, and the continent code.
|
27
|
+
|
28
|
+
# Use the city database:
|
29
|
+
GeoIP.new('GeoLiteCity.dat').country('www.atlantis.sk')
|
30
|
+
=> ["www.atlantis.sk", "217.67.18.26", "SK", "SVK", "Slovakia", "EU", "02", "Bratislava", "", 48.15, 17.1167, nil, nil, "Europe/Bratislava"]
|
25
31
|
|
26
32
|
GeoIP.new('GeoCity.dat').city('github.com')
|
27
33
|
=> ["github.com", "207.97.227.239", "US", "USA", "United States", "NA", "CA", "San Francisco", "94110", 37.7484, -122.4156, 807, 415, "America/Los_Angeles"]
|
28
34
|
|
29
|
-
Returned values are the
|
35
|
+
Returned values are the requested hostname, the IP address as a dotted quad,
|
36
|
+
the ISO3166-1 alpha-2 country code, the ISO3166-2 alpha-3 country code, the
|
37
|
+
ISO3166 country name, the continent code, the region (state or territory) name,
|
30
38
|
city name, postal_code/zipcode, latitude, longitude, USA DMA code, USA area code,
|
31
|
-
timezone name.
|
39
|
+
timezone name.
|
40
|
+
|
41
|
+
Result arrays from both city and country also contain accessor methods as appropriate:
|
42
|
+
request, ip, country_code, country_code2, country_code3, country_name, continent_code,
|
43
|
+
region_name, city_name, postal_code, latitude, longitude, dma_code, area_code, timezone
|
32
44
|
|
33
45
|
GeoIP.new('GeoIPASNum.dat').asn("www.fsb.ru")
|
34
46
|
=> ["AS8342", "RTComm.RU Autonomous System"]
|
data/lib/geoip.rb
CHANGED
@@ -50,8 +50,11 @@ rescue LoadError
|
|
50
50
|
end
|
51
51
|
|
52
52
|
class GeoIP
|
53
|
-
|
53
|
+
# The GeoIP GEM version number
|
54
|
+
VERSION = "0.9.0"
|
55
|
+
|
54
56
|
private
|
57
|
+
# Ordered list of the ISO3166 2-character country codes, ordered by GeoIP ID
|
55
58
|
CountryCode = [
|
56
59
|
"--","AP","EU","AD","AE","AF","AG","AI","AL","AM","AN",
|
57
60
|
"AO","AQ","AR","AS","AT","AU","AW","AZ","BA","BB",
|
@@ -81,6 +84,7 @@ class GeoIP
|
|
81
84
|
"BL","MF"
|
82
85
|
]
|
83
86
|
|
87
|
+
# Ordered list of the ISO3166 3-character country codes, ordered by GeoIP ID
|
84
88
|
CountryCode3 = [
|
85
89
|
"--","AP","EU","AND","ARE","AFG","ATG","AIA","ALB","ARM","ANT",
|
86
90
|
"AGO","AQ","ARG","ASM","AUT","AUS","ABW","AZE","BIH","BRB",
|
@@ -110,6 +114,7 @@ class GeoIP
|
|
110
114
|
"BLM","MAF"
|
111
115
|
]
|
112
116
|
|
117
|
+
# Ordered list of the English names of the countries, ordered by GeoIP ID
|
113
118
|
CountryName = [
|
114
119
|
"N/A",
|
115
120
|
"Asia/Pacific Region",
|
@@ -366,6 +371,7 @@ class GeoIP
|
|
366
371
|
"Saint Martin"
|
367
372
|
]
|
368
373
|
|
374
|
+
# Ordered list of the ISO3166 2-character continent code of the countries, ordered by GeoIP ID
|
369
375
|
CountryContinent = [
|
370
376
|
"--","AS","EU","EU","AS","AS","SA","SA","EU","AS","SA",
|
371
377
|
"AF","AN","SA","OC","EU","OC","SA","AS","EU","SA",
|
@@ -395,6 +401,7 @@ class GeoIP
|
|
395
401
|
"SA","SA"
|
396
402
|
]
|
397
403
|
|
404
|
+
# Hash of the timezone codes mapped to timezone name, per zoneinfo
|
398
405
|
TimeZone = {
|
399
406
|
"USAL" => "America/Chicago", "USAK" => "America/Anchorage", "USAZ" => "America/Phoenix",
|
400
407
|
"USAR" => "America/Chicago", "USCA" => "America/Los_Angeles", "USCO" => "America/Denver",
|
@@ -624,37 +631,36 @@ class GeoIP
|
|
624
631
|
}
|
625
632
|
|
626
633
|
public
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
GEOIP_NETSPEED_EDITION,
|
638
|
-
) = *1..10
|
634
|
+
GEOIP_COUNTRY_EDITION = 1
|
635
|
+
GEOIP_CITY_EDITION_REV1 = 2
|
636
|
+
GEOIP_REGION_EDITION_REV1 = 3
|
637
|
+
GEOIP_ISP_EDITION = 4
|
638
|
+
GEOIP_ORG_EDITION = 5
|
639
|
+
GEOIP_CITY_EDITION_REV0 = 6
|
640
|
+
GEOIP_REGION_EDITION_REV0 = 7
|
641
|
+
GEOIP_PROXY_EDITION = 8
|
642
|
+
GEOIP_ASNUM_EDITION = 9
|
643
|
+
GEOIP_NETSPEED_EDITION = 10
|
639
644
|
|
640
645
|
private
|
641
|
-
COUNTRY_BEGIN = 16776960
|
642
|
-
STATE_BEGIN_REV0 = 16700000
|
643
|
-
STATE_BEGIN_REV1 = 16000000
|
644
|
-
STRUCTURE_INFO_MAX_SIZE = 20
|
645
|
-
DATABASE_INFO_MAX_SIZE = 100
|
646
|
-
MAX_ORG_RECORD_LENGTH = 300
|
647
|
-
MAX_ASN_RECORD_LENGTH = 300
|
648
|
-
US_OFFSET = 1
|
649
|
-
CANADA_OFFSET = 677
|
650
|
-
WORLD_OFFSET = 1353
|
651
|
-
FIPS_RANGE = 360
|
652
|
-
FULL_RECORD_LENGTH = 50
|
646
|
+
COUNTRY_BEGIN = 16776960 #:nodoc:
|
647
|
+
STATE_BEGIN_REV0 = 16700000 #:nodoc:
|
648
|
+
STATE_BEGIN_REV1 = 16000000 #:nodoc:
|
649
|
+
STRUCTURE_INFO_MAX_SIZE = 20 #:nodoc:
|
650
|
+
DATABASE_INFO_MAX_SIZE = 100 #:nodoc:
|
651
|
+
MAX_ORG_RECORD_LENGTH = 300 #:nodoc:
|
652
|
+
MAX_ASN_RECORD_LENGTH = 300 #:nodoc: unverified
|
653
|
+
US_OFFSET = 1 #:nodoc:
|
654
|
+
CANADA_OFFSET = 677 #:nodoc:
|
655
|
+
WORLD_OFFSET = 1353 #:nodoc:
|
656
|
+
FIPS_RANGE = 360 #:nodoc:
|
657
|
+
FULL_RECORD_LENGTH = 50 #:nodoc:
|
653
658
|
|
654
|
-
STANDARD_RECORD_LENGTH = 3
|
655
|
-
SEGMENT_RECORD_LENGTH = 3
|
659
|
+
STANDARD_RECORD_LENGTH = 3 #:nodoc:
|
660
|
+
SEGMENT_RECORD_LENGTH = 3 #:nodoc:
|
656
661
|
|
657
662
|
public
|
663
|
+
# The Edition number that identifies which kind of database you've opened
|
658
664
|
attr_reader :databaseType
|
659
665
|
|
660
666
|
# Open the GeoIP database and determine the file format version
|
@@ -710,15 +716,20 @@ class GeoIP
|
|
710
716
|
# Search the GeoIP database for the specified host, returning country info
|
711
717
|
#
|
712
718
|
# +hostname+ is a String holding the host's DNS name or numeric IP address.
|
713
|
-
#
|
719
|
+
# If the database is a City database (normal), return the result that +city+ would return.
|
720
|
+
# Otherwise, return an array of seven elements:
|
714
721
|
# * The host or IP address string as requested
|
715
722
|
# * The IP address string after looking up the host
|
716
|
-
# * The GeoIP country-ID as an integer
|
717
|
-
# * The
|
718
|
-
# * The
|
719
|
-
# * The
|
723
|
+
# * The GeoIP country-ID as an integer (N.B. this is excluded from the city results!)
|
724
|
+
# * The two-character country code (ISO 3166-1 alpha-2)
|
725
|
+
# * The three-character country code (ISO 3166-2 alpha-3)
|
726
|
+
# * The ISO 3166 English-language name of the country
|
720
727
|
# * The two-character continent code
|
721
728
|
#
|
729
|
+
# The array has been extended with methods listed in GeoIP::CountryAccessors.ACCESSORS:
|
730
|
+
# request, ip, country_code, country_code2, country_code3, country_name, continent_code.
|
731
|
+
# In addition, +to_hash+ provides a symbol-keyed hash for the above values.
|
732
|
+
#
|
722
733
|
def country(hostname)
|
723
734
|
if (@databaseType == GEOIP_CITY_EDITION_REV0 ||
|
724
735
|
@databaseType == GEOIP_CITY_EDITION_REV1)
|
@@ -734,7 +745,7 @@ class GeoIP
|
|
734
745
|
|
735
746
|
# Convert numeric IP address to an integer
|
736
747
|
ipnum = iptonum(ip)
|
737
|
-
if (@databaseType != GEOIP_COUNTRY_EDITION &&
|
748
|
+
if (@databaseType != GEOIP_COUNTRY_EDITION &&
|
738
749
|
@databaseType != GEOIP_PROXY_EDITION &&
|
739
750
|
@databaseType != GEOIP_NETSPEED_EDITION)
|
740
751
|
throw "Invalid GeoIP database type, can't look up Country by IP"
|
@@ -743,118 +754,36 @@ class GeoIP
|
|
743
754
|
[ hostname, # Requested hostname
|
744
755
|
ip, # Ip address as dotted quad
|
745
756
|
code, # GeoIP's country code
|
746
|
-
CountryCode[code], # ISO3166-1 code
|
747
|
-
CountryCode3[code], # ISO3166-2 code
|
748
|
-
CountryName[code], # Country name, per
|
749
|
-
CountryContinent[code]
|
750
|
-
|
751
|
-
|
752
|
-
# Search the GeoIP database for the specified host, returning city info
|
753
|
-
#
|
754
|
-
# +hostname+ is a String holding the host's DNS name or numeric IP address
|
755
|
-
# Return an array of twelve or fourteen elements:
|
756
|
-
# * All elements from the country query
|
757
|
-
# * The region (state or territory) name
|
758
|
-
# * The city name
|
759
|
-
# * The postal code (zipcode)
|
760
|
-
# * The latitude
|
761
|
-
# * The longitude
|
762
|
-
# * The dma_code and area_code, if available (REV1 City database)
|
763
|
-
# * The timezone name, if known
|
764
|
-
private
|
765
|
-
|
766
|
-
def read_city(pos, hostname = '', ip = '')
|
767
|
-
off = pos + (2*@record_length-1) * @databaseSegments[0]
|
768
|
-
record = atomic_read(FULL_RECORD_LENGTH, off)
|
769
|
-
return nil unless record && record.size == FULL_RECORD_LENGTH
|
770
|
-
|
771
|
-
# The country code is the first byte:
|
772
|
-
code = record[0]
|
773
|
-
code = code.ord if code.respond_to?(:ord)
|
774
|
-
record = record[1..-1]
|
775
|
-
@iter_pos += 1 unless @iter_pos.nil?
|
776
|
-
|
777
|
-
spl = record.split("\x00", 4)
|
778
|
-
# Get the region:
|
779
|
-
region = spl[0]
|
780
|
-
@iter_pos += (region.size + 1) unless @iter_pos.nil?
|
781
|
-
|
782
|
-
# Get the city:
|
783
|
-
city = spl[1]
|
784
|
-
@iter_pos += (city.size + 1) unless @iter_pos.nil?
|
785
|
-
# set the correct encoding in ruby 1.9 compatible environments:
|
786
|
-
city.force_encoding('iso-8859-1') if city.respond_to?(:force_encoding)
|
787
|
-
|
788
|
-
# Get the postal code:
|
789
|
-
postal_code = spl[2]
|
790
|
-
@iter_pos += (postal_code.size + 1) unless @iter_pos.nil?
|
791
|
-
|
792
|
-
record = spl[3]
|
793
|
-
# Get the latitude/longitude:
|
794
|
-
if(record && record[0,3]) then
|
795
|
-
latitude = le_to_ui(record[0,3].unpack('C*')) / 10000.0 - 180
|
796
|
-
record = record[3..-1]
|
797
|
-
@iter_pos += 3 unless @iter_pos.nil?
|
798
|
-
else
|
799
|
-
latitude = ''
|
800
|
-
end
|
801
|
-
if(record && record[0,3]) then
|
802
|
-
longitude = le_to_ui(record[0,3].unpack('C*')) / 10000.0 - 180
|
803
|
-
record = record[3..-1]
|
804
|
-
@iter_pos += 3 unless @iter_pos.nil?
|
805
|
-
else
|
806
|
-
longitude = ''
|
807
|
-
end
|
808
|
-
|
809
|
-
us_area_codes = []
|
810
|
-
if (record &&
|
811
|
-
record[0,3] &&
|
812
|
-
@databaseType == GEOIP_CITY_EDITION_REV1 &&
|
813
|
-
CountryCode[code] == "US") # UNTESTED
|
814
|
-
dmaarea_combo = le_to_ui(record[0,3].unpack('C*'))
|
815
|
-
dma_code = dmaarea_combo / 1000;
|
816
|
-
area_code = dmaarea_combo % 1000;
|
817
|
-
us_area_codes = [ dma_code, area_code ]
|
818
|
-
@iter_pos += 3 unless @iter_pos.nil?
|
819
|
-
else
|
820
|
-
us_area_codes = [ nil, nil ] # Ensure that TimeZone is always at the same offset
|
821
|
-
end
|
822
|
-
|
823
|
-
[ hostname, # Requested hostname
|
824
|
-
ip, # Ip address as dotted quad
|
825
|
-
CountryCode[code], # ISO3166-1 code
|
826
|
-
CountryCode3[code], # ISO3166-2 code
|
827
|
-
CountryName[code], # Country name, per IS03166
|
828
|
-
CountryContinent[code], # Continent code.
|
829
|
-
region, # Region name
|
830
|
-
city, # City name
|
831
|
-
postal_code, # Postal code
|
832
|
-
latitude,
|
833
|
-
longitude,
|
834
|
-
] +
|
835
|
-
us_area_codes +
|
836
|
-
[ TimeZone["#{CountryCode[code]}#{region}"] || TimeZone["#{CountryCode[code]}"] ]
|
757
|
+
CountryCode[code], # ISO3166-1 alpha-2 code
|
758
|
+
CountryCode3[code], # ISO3166-2 alpha-3 code
|
759
|
+
CountryName[code], # Country name, per ISO 3166
|
760
|
+
CountryContinent[code] # Continent code.
|
761
|
+
].extend(CountryAccessors)
|
837
762
|
end
|
838
763
|
|
839
|
-
public
|
840
|
-
|
841
764
|
# Search the GeoIP database for the specified host, returning city info.
|
842
765
|
#
|
843
766
|
# +hostname+ is a String holding the host's DNS name or numeric IP address.
|
844
|
-
# Return an array of
|
767
|
+
# Return an array of fourteen elements:
|
845
768
|
# * The host or IP address string as requested
|
846
769
|
# * The IP address string after looking up the host
|
847
|
-
# * The
|
848
|
-
# * The
|
849
|
-
# * The
|
850
|
-
# * The ISO3166 English-language name of the country
|
770
|
+
# * The two-character country code (ISO 3166-1 alpha-2)
|
771
|
+
# * The three-character country code (ISO 3166-2 alpha-3)
|
772
|
+
# * The ISO 3166 English-language name of the country
|
851
773
|
# * The two-character continent code
|
852
|
-
# * The region name
|
774
|
+
# * The region name (state or territory)
|
853
775
|
# * The city name
|
854
|
-
# * The postal code
|
776
|
+
# * The postal code (zipcode)
|
855
777
|
# * The latitude
|
856
778
|
# * The longitude
|
857
|
-
# * The USA dma_code
|
779
|
+
# * The USA dma_code if known (only REV1 City database)
|
780
|
+
# * The USA area_code if known (only REV1 City database)
|
781
|
+
# * The timezone name, if known
|
782
|
+
#
|
783
|
+
# The array has been extended with methods listed in GeoIP::CityAccessors.ACCESSORS:
|
784
|
+
# request, ip, country_code2, country_code3, country_name, continent_code,
|
785
|
+
# region_name, city_name, postal_code, latitude, longitude, dma_code, area_code, timezone.
|
786
|
+
# In addition, +to_hash+ provides a symbol-keyed hash for the above values.
|
858
787
|
#
|
859
788
|
def city(hostname)
|
860
789
|
ip = hostname
|
@@ -879,10 +808,11 @@ class GeoIP
|
|
879
808
|
# and I'll send you the test program so you can test whatever IP range you think is causing
|
880
809
|
# problems, as I don't care to undertake an exhaustive search of the 32-bit space.
|
881
810
|
return nil if pos == @databaseSegments[0]
|
882
|
-
read_city(pos, hostname, ip)
|
811
|
+
read_city(pos, hostname, ip).extend(CityAccessors)
|
883
812
|
end
|
884
813
|
|
885
814
|
# Search a ISP GeoIP database for the specified host, returning the ISP
|
815
|
+
# Not all GeoIP databases contain ISP information. Check http://maxmind.com
|
886
816
|
#
|
887
817
|
# +hostname+ is a String holding the host's DNS name or numeric IP address.
|
888
818
|
# Return the ISP name
|
@@ -906,7 +836,7 @@ class GeoIP
|
|
906
836
|
record = record.sub(/\000.*/n, '')
|
907
837
|
record
|
908
838
|
end
|
909
|
-
|
839
|
+
|
910
840
|
# Search a ASN GeoIP database for the specified host, returning the AS number + description
|
911
841
|
#
|
912
842
|
# +hostname+ is a String holding the host's DNS name or numeric IP address.
|
@@ -914,7 +844,7 @@ class GeoIP
|
|
914
844
|
#
|
915
845
|
# Source:
|
916
846
|
# http://geolite.maxmind.com/download/geoip/database/asnum/GeoIPASNum.dat.gz
|
917
|
-
#
|
847
|
+
#
|
918
848
|
def asn(hostname)
|
919
849
|
ip = hostname
|
920
850
|
if ip.kind_of?(String) && ip !~ /^[0-9.]*$/
|
@@ -932,10 +862,10 @@ class GeoIP
|
|
932
862
|
off = pos + (2*@record_length-1) * @databaseSegments[0]
|
933
863
|
record = atomic_read(MAX_ASN_RECORD_LENGTH, off)
|
934
864
|
record = record.sub(/\000.*/n, '')
|
935
|
-
|
865
|
+
|
936
866
|
if record =~ /^(AS\d+)\s(.*)$/
|
937
|
-
# AS####, Description
|
938
|
-
return [$1, $2]
|
867
|
+
# AS####, Description
|
868
|
+
return [$1, $2].extend(ASNAccessors)
|
939
869
|
end
|
940
870
|
end
|
941
871
|
|
@@ -964,8 +894,92 @@ class GeoIP
|
|
964
894
|
end
|
965
895
|
|
966
896
|
private
|
967
|
-
|
968
|
-
|
897
|
+
|
898
|
+
# Search the GeoIP database for the specified host, returning city info
|
899
|
+
#
|
900
|
+
# +hostname+ is a String holding the host's DNS name or numeric IP address
|
901
|
+
# Return an array of fourteen elements:
|
902
|
+
# * All elements from the country query (except GeoIP's country code, bah!)
|
903
|
+
# * The region (state or territory) name
|
904
|
+
# * The city name
|
905
|
+
# * The postal code (zipcode)
|
906
|
+
# * The latitude
|
907
|
+
# * The longitude
|
908
|
+
# * The dma_code and area_code, if available (REV1 City database)
|
909
|
+
# * The timezone name, if known
|
910
|
+
def read_city(pos, hostname = '', ip = '') #:nodoc:
|
911
|
+
off = pos + (2*@record_length-1) * @databaseSegments[0]
|
912
|
+
record = atomic_read(FULL_RECORD_LENGTH, off)
|
913
|
+
return nil unless record && record.size == FULL_RECORD_LENGTH
|
914
|
+
|
915
|
+
# The country code is the first byte:
|
916
|
+
code = record[0]
|
917
|
+
code = code.ord if code.respond_to?(:ord)
|
918
|
+
record = record[1..-1]
|
919
|
+
@iter_pos += 1 unless @iter_pos.nil?
|
920
|
+
|
921
|
+
spl = record.split("\x00", 4)
|
922
|
+
# Get the region:
|
923
|
+
region = spl[0]
|
924
|
+
@iter_pos += (region.size + 1) unless @iter_pos.nil?
|
925
|
+
|
926
|
+
# Get the city:
|
927
|
+
city = spl[1]
|
928
|
+
@iter_pos += (city.size + 1) unless @iter_pos.nil?
|
929
|
+
# set the correct encoding in ruby 1.9 compatible environments:
|
930
|
+
city.force_encoding('iso-8859-1') if city.respond_to?(:force_encoding)
|
931
|
+
|
932
|
+
# Get the postal code:
|
933
|
+
postal_code = spl[2]
|
934
|
+
@iter_pos += (postal_code.size + 1) unless @iter_pos.nil?
|
935
|
+
|
936
|
+
record = spl[3]
|
937
|
+
# Get the latitude/longitude:
|
938
|
+
if(record && record[0,3]) then
|
939
|
+
latitude = le_to_ui(record[0,3].unpack('C*')) / 10000.0 - 180
|
940
|
+
record = record[3..-1]
|
941
|
+
@iter_pos += 3 unless @iter_pos.nil?
|
942
|
+
else
|
943
|
+
latitude = ''
|
944
|
+
end
|
945
|
+
if(record && record[0,3]) then
|
946
|
+
longitude = le_to_ui(record[0,3].unpack('C*')) / 10000.0 - 180
|
947
|
+
record = record[3..-1]
|
948
|
+
@iter_pos += 3 unless @iter_pos.nil?
|
949
|
+
else
|
950
|
+
longitude = ''
|
951
|
+
end
|
952
|
+
|
953
|
+
if (record &&
|
954
|
+
record[0,3] &&
|
955
|
+
@databaseType == GEOIP_CITY_EDITION_REV1 &&
|
956
|
+
CountryCode[code] == "US") # UNTESTED
|
957
|
+
dmaarea_combo = le_to_ui(record[0,3].unpack('C*'))
|
958
|
+
dma_code = dmaarea_combo / 1000;
|
959
|
+
area_code = dmaarea_combo % 1000;
|
960
|
+
@iter_pos += 3 unless @iter_pos.nil?
|
961
|
+
else
|
962
|
+
dma_code, area_code = nil, nil
|
963
|
+
end
|
964
|
+
|
965
|
+
[ hostname, # Requested hostname
|
966
|
+
ip, # Ip address as dotted quad
|
967
|
+
CountryCode[code], # ISO3166-1 code
|
968
|
+
CountryCode3[code], # ISO3166-2 code
|
969
|
+
CountryName[code], # Country name, per IS03166
|
970
|
+
CountryContinent[code], # Continent code.
|
971
|
+
region, # Region name
|
972
|
+
city, # City name
|
973
|
+
postal_code, # Postal code
|
974
|
+
latitude,
|
975
|
+
longitude,
|
976
|
+
dma_code,
|
977
|
+
area_code
|
978
|
+
] +
|
979
|
+
[ TimeZone["#{CountryCode[code]}#{region}"] || TimeZone["#{CountryCode[code]}"] ]
|
980
|
+
end
|
981
|
+
|
982
|
+
def iptonum(ip) #:nodoc: Convert numeric IP address to integer
|
969
983
|
if ip.kind_of?(String) &&
|
970
984
|
ip =~ /^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$/
|
971
985
|
ip = be_to_ui(Regexp.last_match().to_a.slice(1..4))
|
@@ -973,7 +987,7 @@ class GeoIP
|
|
973
987
|
ip
|
974
988
|
end
|
975
989
|
|
976
|
-
def seek_record(ipnum)
|
990
|
+
def seek_record(ipnum) #:nodoc:
|
977
991
|
# Binary search in the file.
|
978
992
|
# Records are pairs of little-endian integers, each of @record_length.
|
979
993
|
offset = 0
|
@@ -989,14 +1003,14 @@ class GeoIP
|
|
989
1003
|
end
|
990
1004
|
|
991
1005
|
# Convert a big-endian array of numeric bytes to unsigned int
|
992
|
-
def be_to_ui(s)
|
1006
|
+
def be_to_ui(s) #:nodoc:
|
993
1007
|
s.inject(0) { |m, o|
|
994
1008
|
(m << 8) + o.to_i
|
995
1009
|
}
|
996
1010
|
end
|
997
1011
|
|
998
1012
|
# Same for little-endian
|
999
|
-
def le_to_ui(s)
|
1013
|
+
def le_to_ui(s) #:nodoc:
|
1000
1014
|
be_to_ui(s.reverse)
|
1001
1015
|
end
|
1002
1016
|
|
@@ -1005,7 +1019,7 @@ class GeoIP
|
|
1005
1019
|
# and multiprocess-safe). Otherwise we'll use a mutex to synchronize
|
1006
1020
|
# access (only providing protection against multiple threads, but not
|
1007
1021
|
# file descriptors shared across multiple processes).
|
1008
|
-
def atomic_read(length, offset)
|
1022
|
+
def atomic_read(length, offset) #:nodoc:
|
1009
1023
|
if @mutex
|
1010
1024
|
@mutex.synchronize {
|
1011
1025
|
@file.seek(offset)
|
@@ -1015,6 +1029,49 @@ class GeoIP
|
|
1015
1029
|
IO.pread(@file.fileno, length, offset)
|
1016
1030
|
end
|
1017
1031
|
end
|
1032
|
+
|
1033
|
+
module CountryAccessors #:nodoc:
|
1034
|
+
ACCESSORS = [
|
1035
|
+
:request, :ip, :country_code, :country_code2, :country_code3, :country_name, :continent_code
|
1036
|
+
]
|
1037
|
+
ACCESSORS.each_with_index do |method, i|
|
1038
|
+
define_method(method) { self[i] }
|
1039
|
+
end
|
1040
|
+
|
1041
|
+
def to_hash
|
1042
|
+
ACCESSORS.inject({}) do |hash, key|
|
1043
|
+
hash[key] = self.send(key)
|
1044
|
+
hash
|
1045
|
+
end
|
1046
|
+
end
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
module CityAccessors #:nodoc:
|
1050
|
+
ACCESSORS = [
|
1051
|
+
:request, :ip, :country_code2, :country_code3, :country_name, :continent_code,
|
1052
|
+
:region_name, :city_name, :postal_code, :latitude, :longitude, :dma_code, :area_code, :timezone
|
1053
|
+
]
|
1054
|
+
ACCESSORS.each_with_index do |method, i|
|
1055
|
+
define_method(method) { self[i] }
|
1056
|
+
end
|
1057
|
+
|
1058
|
+
def to_hash
|
1059
|
+
ACCESSORS.inject({}) do |hash, key|
|
1060
|
+
hash[key] = self.send(key)
|
1061
|
+
hash
|
1062
|
+
end
|
1063
|
+
end
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
module ASNAccessors #:nodoc:
|
1067
|
+
def ip
|
1068
|
+
self[0]
|
1069
|
+
end
|
1070
|
+
|
1071
|
+
def asn
|
1072
|
+
self[1]
|
1073
|
+
end
|
1074
|
+
end
|
1018
1075
|
end
|
1019
1076
|
|
1020
1077
|
if $0 == __FILE__
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: geoip
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 59
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
- 8
|
9
8
|
- 9
|
10
|
-
|
9
|
+
- 0
|
10
|
+
version: 0.9.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Clifford Heath
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2011-
|
19
|
+
date: 2011-02-07 00:00:00 +11:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|