geoip 1.1.2 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +4 -0
- data/README.rdoc +20 -11
- data/Rakefile +1 -1
- data/geoip.gemspec +4 -4
- data/lib/geoip.rb +50 -16
- metadata +4 -4
data/History.rdoc
CHANGED
data/README.rdoc
CHANGED
@@ -13,6 +13,11 @@ and the city, ISP and other information, if you have that database version.
|
|
13
13
|
Includes support for ASN data files, thanks to Roland Matiz.
|
14
14
|
This release adds support for timezone names, thanks to Tonni Aagesen.
|
15
15
|
|
16
|
+
If you have required 'io/extra' and have IO#pread, cross-process file-descriptor sharing is enabled.
|
17
|
+
Each GeoIP instance keeps the file descriptor open, with a Mutex for thread-safety.
|
18
|
+
You should consider this if your process will fork without exec, as
|
19
|
+
{modrails does}[http://www.modrails.com/documentation/Users%20guide%20Nginx.html#_smart_spawning_gotcha_1_unintential_file_descriptor_sharing]
|
20
|
+
|
16
21
|
== SYNOPSIS:
|
17
22
|
|
18
23
|
require 'geoip'
|
@@ -25,9 +30,9 @@ This release adds support for timezone names, thanks to Tonni Aagesen.
|
|
25
30
|
c.to_hash
|
26
31
|
=> {:country_code3=>"FIN", :country_name=>"Finland", :continent_code=>"EU", :request=>"www.nokia.com", :country_code=>69, :country_code2=>"FI", :ip=>"147.243.3.83"}
|
27
32
|
|
28
|
-
|
29
|
-
|
30
|
-
|
33
|
+
Returned values are the requested hostname, the IP address as a dotted quad,
|
34
|
+
Maxmind's country code, the ISO3166-1 alpha-2 country code, the ISO3166-2 alpha-3
|
35
|
+
country code, the ISO3166 country name, and the continent code.
|
31
36
|
|
32
37
|
# Use the city database:
|
33
38
|
c = GeoIP.new('GeoLiteCity.dat').city('github.com')
|
@@ -40,15 +45,19 @@ This release adds support for timezone names, thanks to Tonni Aagesen.
|
|
40
45
|
GeoIP.new('GeoCity.dat').city('github.com')
|
41
46
|
=> ["github.com", "207.97.227.239", "US", "USA", "United States", "NA", "CA", "San Francisco", "94110", 37.7484, -122.4156, 807, 415, "America/Los_Angeles"]
|
42
47
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
+
# Use the city ipv6 database:
|
49
|
+
GeoIP.new('GeoLiteCityv6.dat').city('::151.38.39.114')
|
50
|
+
=> ["::151.38.39.114", "::151.38.39.114", "IT", "ITA", "Italy", "EU", "05", "Piacenza", "", 45.016699999999986, 9.666699999999992, nil, nil, "Europe/Rome"]
|
51
|
+
|
52
|
+
Returned values are the requested hostname, the IP address as a dotted quad,
|
53
|
+
the ISO3166-1 alpha-2 country code, the ISO3166-2 alpha-3 country code, the
|
54
|
+
ISO3166 country name, the continent code, the region (state or territory) name,
|
55
|
+
city name, postal_code/zipcode, latitude, longitude, USA DMA code, USA area code,
|
56
|
+
timezone name.
|
48
57
|
|
49
|
-
|
50
|
-
|
51
|
-
|
58
|
+
Result arrays from both city and country have mixed-in accessor methods as appropriate:
|
59
|
+
request, ip, country_code, country_code2, country_code3, country_name, continent_code,
|
60
|
+
region_name, city_name, postal_code, latitude, longitude, dma_code, area_code, timezone
|
52
61
|
|
53
62
|
GeoIP.new('GeoIPASNum.dat').asn("www.fsb.ru")
|
54
63
|
=> ["AS8342", "RTComm.RU Autonomous System"]
|
data/Rakefile
CHANGED
@@ -9,7 +9,7 @@ Jeweler::Tasks.new do |gem|
|
|
9
9
|
gem.name = "geoip"
|
10
10
|
gem.version = GeoIP::VERSION
|
11
11
|
gem.homepage = "http://github.com/cjheath/geoip"
|
12
|
-
gem.license = "
|
12
|
+
gem.license = "GPL"
|
13
13
|
gem.summary = %Q{GeoIP searches a GeoIP database for a given host or IP address, and returns information about the country where the IP address is allocated, and the city, ISP and other information, if you have that database version.}
|
14
14
|
gem.description = %Q{GeoIP searches a GeoIP database for a given host or IP address, and
|
15
15
|
returns information about the country where the IP address is allocated,
|
data/geoip.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "geoip"
|
8
|
-
s.version = "1.
|
8
|
+
s.version = "1.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Clifford Heath", "Roland Moriz"]
|
12
|
-
s.date = "2012-
|
12
|
+
s.date = "2012-10-16"
|
13
13
|
s.description = "GeoIP searches a GeoIP database for a given host or IP address, and\nreturns information about the country where the IP address is allocated,\nand the city, ISP and other information, if you have that database version."
|
14
14
|
s.email = ["clifford.heath@gmail.com", "rmoriz@gmail.com"]
|
15
15
|
s.executables = ["geoip"]
|
@@ -40,9 +40,9 @@ Gem::Specification.new do |s|
|
|
40
40
|
"website/template.rhtml"
|
41
41
|
]
|
42
42
|
s.homepage = "http://github.com/cjheath/geoip"
|
43
|
-
s.licenses = ["
|
43
|
+
s.licenses = ["GPL"]
|
44
44
|
s.require_paths = ["lib"]
|
45
|
-
s.rubygems_version = "1.8.
|
45
|
+
s.rubygems_version = "1.8.24"
|
46
46
|
s.summary = "GeoIP searches a GeoIP database for a given host or IP address, and returns information about the country where the IP address is allocated, and the city, ISP and other information, if you have that database version."
|
47
47
|
|
48
48
|
if s.respond_to? :specification_version then
|
data/lib/geoip.rb
CHANGED
@@ -48,13 +48,18 @@ begin
|
|
48
48
|
rescue LoadError
|
49
49
|
# oh well, hope they're not forking after initializing
|
50
50
|
end
|
51
|
+
begin
|
52
|
+
require 'ipaddr' # Needed for IPv6 support
|
53
|
+
rescue LoadError
|
54
|
+
# Won't work for an IPv6 database
|
55
|
+
end
|
51
56
|
|
52
57
|
require 'yaml'
|
53
58
|
|
54
59
|
class GeoIP
|
55
60
|
|
56
61
|
# The GeoIP GEM version number
|
57
|
-
VERSION = "1.
|
62
|
+
VERSION = "1.2.0"
|
58
63
|
|
59
64
|
# The +data/+ directory for geoip
|
60
65
|
DATA_DIR = File.expand_path(File.join(File.dirname(__FILE__),'..','data','geoip'))
|
@@ -87,6 +92,7 @@ class GeoIP
|
|
87
92
|
GEOIP_PROXY_EDITION = 8
|
88
93
|
GEOIP_ASNUM_EDITION = 9
|
89
94
|
GEOIP_NETSPEED_EDITION = 10
|
95
|
+
GEOIP_CITY_EDITION_REV1_V6 = 30
|
90
96
|
|
91
97
|
COUNTRY_BEGIN = 16776960 #:nodoc:
|
92
98
|
STATE_BEGIN_REV0 = 16700000 #:nodoc:
|
@@ -171,21 +177,21 @@ class GeoIP
|
|
171
177
|
#
|
172
178
|
def country(hostname)
|
173
179
|
if (@database_type == GEOIP_CITY_EDITION_REV0 ||
|
174
|
-
@database_type == GEOIP_CITY_EDITION_REV1
|
180
|
+
@database_type == GEOIP_CITY_EDITION_REV1 ||
|
181
|
+
@database_type == GEOIP_CITY_EDITION_REV1_V6)
|
175
182
|
return city(hostname)
|
176
183
|
end
|
177
184
|
|
178
|
-
ip = lookup_ip(hostname)
|
179
|
-
|
180
|
-
# Convert numeric IP address to an integer
|
181
|
-
ipnum = iptonum(ip)
|
182
|
-
|
183
185
|
if (@database_type != GEOIP_COUNTRY_EDITION &&
|
184
186
|
@database_type != GEOIP_PROXY_EDITION &&
|
185
187
|
@database_type != GEOIP_NETSPEED_EDITION)
|
186
188
|
throw "Invalid GeoIP database type, can't look up Country by IP"
|
187
189
|
end
|
188
190
|
|
191
|
+
ip = lookup_ip(hostname)
|
192
|
+
|
193
|
+
ipnum = iptonum(ip) # Convert numeric IP address to an integer
|
194
|
+
|
189
195
|
code = (seek_record(ipnum) - COUNTRY_BEGIN)
|
190
196
|
|
191
197
|
Country.new(
|
@@ -223,16 +229,18 @@ class GeoIP
|
|
223
229
|
def city(hostname)
|
224
230
|
ip = lookup_ip(hostname)
|
225
231
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
232
|
+
if (@database_type == GEOIP_CITY_EDITION_REV0 ||
|
233
|
+
@database_type == GEOIP_CITY_EDITION_REV1)
|
234
|
+
# Convert numeric IP address to an integer
|
235
|
+
ipnum = iptonum(ip)
|
236
|
+
pos = seek_record(ipnum)
|
237
|
+
elsif (@database_type == GEOIP_CITY_EDITION_REV1_V6)
|
238
|
+
ipaddr = IPAddr.new ip
|
239
|
+
pos = seek_record_v6(ipaddr.to_i)
|
240
|
+
else
|
231
241
|
throw "Invalid GeoIP database type, can't look up City by IP"
|
232
242
|
end
|
233
243
|
|
234
|
-
pos = seek_record(ipnum)
|
235
|
-
|
236
244
|
# This next statement was added to MaxMind's C version after it was
|
237
245
|
# rewritten in Ruby. It prevents unassigned IP addresses from returning
|
238
246
|
# bogus data. There was concern over whether the changes to an
|
@@ -361,6 +369,7 @@ class GeoIP
|
|
361
369
|
@database_segments = [STATE_BEGIN_REV1]
|
362
370
|
elsif (@database_type == GEOIP_CITY_EDITION_REV0 ||
|
363
371
|
@database_type == GEOIP_CITY_EDITION_REV1 ||
|
372
|
+
@database_type == GEOIP_CITY_EDITION_REV1_V6 ||
|
364
373
|
@database_type == GEOIP_ORG_EDITION ||
|
365
374
|
@database_type == GEOIP_ISP_EDITION ||
|
366
375
|
@database_type == GEOIP_ASNUM_EDITION)
|
@@ -487,9 +496,11 @@ class GeoIP
|
|
487
496
|
end
|
488
497
|
|
489
498
|
def lookup_ip(ip_or_hostname) # :nodoc:
|
490
|
-
|
499
|
+
if !ip_or_hostname.kind_of?(String) or ip_or_hostname =~ /^[0-9.]+$/
|
500
|
+
return ip_or_hostname
|
501
|
+
end
|
491
502
|
|
492
|
-
# Lookup IP address, we were given a name
|
503
|
+
# Lookup IP address, we were given a name or IPv6 address
|
493
504
|
ip = IPSocket.getaddress(ip_or_hostname)
|
494
505
|
ip = '0.0.0.0' if ip == '::1'
|
495
506
|
ip
|
@@ -528,6 +539,29 @@ class GeoIP
|
|
528
539
|
end
|
529
540
|
end
|
530
541
|
|
542
|
+
def seek_record_v6(ipnum)
|
543
|
+
|
544
|
+
# Binary search in the file.
|
545
|
+
# Records are pairs of little-endian integers, each of @record_length.
|
546
|
+
offset = 0
|
547
|
+
mask = 1 << 127
|
548
|
+
|
549
|
+
127.downto(0) do |depth|
|
550
|
+
off = (@record_length * 2 * offset)
|
551
|
+
buf = atomic_read(@record_length * 2, off)
|
552
|
+
|
553
|
+
buf.slice!(0...@record_length) if ((ipnum & mask) != 0)
|
554
|
+
offset = le_to_ui(buf[0...@record_length].unpack("C*"))
|
555
|
+
|
556
|
+
if (offset >= @database_segments[0])
|
557
|
+
return offset
|
558
|
+
end
|
559
|
+
|
560
|
+
mask >>= 1
|
561
|
+
end
|
562
|
+
|
563
|
+
end
|
564
|
+
|
531
565
|
# Convert a big-endian array of numeric bytes to unsigned int.
|
532
566
|
#
|
533
567
|
# Returns the unsigned Integer.
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: geoip
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-10-16 00:00:00.000000000 Z
|
14
14
|
dependencies: []
|
15
15
|
description: ! 'GeoIP searches a GeoIP database for a given host or IP address, and
|
16
16
|
|
@@ -49,7 +49,7 @@ files:
|
|
49
49
|
- website/template.rhtml
|
50
50
|
homepage: http://github.com/cjheath/geoip
|
51
51
|
licenses:
|
52
|
-
-
|
52
|
+
- GPL
|
53
53
|
post_install_message:
|
54
54
|
rdoc_options: []
|
55
55
|
require_paths:
|
@@ -68,7 +68,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
68
68
|
version: '0'
|
69
69
|
requirements: []
|
70
70
|
rubyforge_project:
|
71
|
-
rubygems_version: 1.8.
|
71
|
+
rubygems_version: 1.8.24
|
72
72
|
signing_key:
|
73
73
|
specification_version: 3
|
74
74
|
summary: GeoIP searches a GeoIP database for a given host or IP address, and returns
|