geoip 0.8.9 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|