geoip 1.1.2 → 1.2.1
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/History.rdoc +4 -0
- data/README.rdoc +26 -14
- data/Rakefile +2 -2
- data/geoip.gemspec +4 -4
- data/lib/geoip.rb +58 -20
- 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"]
|
|
@@ -76,9 +85,12 @@ This version Copyright (C) 2005 Clifford Heath
|
|
|
76
85
|
Derived from the C version, Copyright (C) 2003 MaxMind LLC
|
|
77
86
|
|
|
78
87
|
This library is free software; you can redistribute it and/or
|
|
79
|
-
modify it under the terms of the GNU General Public
|
|
80
|
-
|
|
81
|
-
|
|
88
|
+
modify it under the terms of the GNU Lesser General Public License,
|
|
89
|
+
as published by the Free Software Foundation; either version 2.1 of
|
|
90
|
+
the License, or (at your option) any later version. This follows the
|
|
91
|
+
license applied by Maxmind to their C library, for example in the
|
|
92
|
+
version here:
|
|
93
|
+
<http://www.maxmind.com/download/geoip/api/c/GeoIP-1.4.2.tar.gz>.
|
|
82
94
|
|
|
83
95
|
This library is distributed in the hope that it will be useful,
|
|
84
96
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
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,
|
|
@@ -31,7 +31,7 @@ Rake::TestTask.new(:test) do |test|
|
|
|
31
31
|
end
|
|
32
32
|
task :default => :test
|
|
33
33
|
|
|
34
|
-
require '
|
|
34
|
+
require 'rdoc/task'
|
|
35
35
|
Rake::RDocTask.new do |rdoc|
|
|
36
36
|
rdoc.rdoc_dir = 'rdoc'
|
|
37
37
|
rdoc.title = "geoip #{GeoIP::VERSION}"
|
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.1
|
|
8
|
+
s.version = "1.2.1"
|
|
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-12-18"
|
|
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.1
|
|
62
|
+
VERSION = "1.2.1"
|
|
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,8 @@ class GeoIP
|
|
|
87
92
|
GEOIP_PROXY_EDITION = 8
|
|
88
93
|
GEOIP_ASNUM_EDITION = 9
|
|
89
94
|
GEOIP_NETSPEED_EDITION = 10
|
|
95
|
+
GEOIP_COUNTRY_EDITION_V6 = 12
|
|
96
|
+
GEOIP_CITY_EDITION_REV1_V6 = 30
|
|
90
97
|
|
|
91
98
|
COUNTRY_BEGIN = 16776960 #:nodoc:
|
|
92
99
|
STATE_BEGIN_REV0 = 16700000 #:nodoc:
|
|
@@ -171,23 +178,25 @@ class GeoIP
|
|
|
171
178
|
#
|
|
172
179
|
def country(hostname)
|
|
173
180
|
if (@database_type == GEOIP_CITY_EDITION_REV0 ||
|
|
174
|
-
@database_type == GEOIP_CITY_EDITION_REV1
|
|
181
|
+
@database_type == GEOIP_CITY_EDITION_REV1 ||
|
|
182
|
+
@database_type == GEOIP_CITY_EDITION_REV1_V6)
|
|
175
183
|
return city(hostname)
|
|
176
184
|
end
|
|
177
185
|
|
|
178
186
|
ip = lookup_ip(hostname)
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
187
|
+
if (@database_type == GEOIP_COUNTRY_EDITION ||
|
|
188
|
+
@database_type == GEOIP_PROXY_EDITION ||
|
|
189
|
+
@database_type == GEOIP_NETSPEED_EDITION)
|
|
190
|
+
# Convert numeric IP address to an integer
|
|
191
|
+
ipnum = iptonum(ip)
|
|
192
|
+
code = (seek_record(ipnum) - COUNTRY_BEGIN)
|
|
193
|
+
elsif @database_type == GEOIP_COUNTRY_EDITION_V6
|
|
194
|
+
ipaddr = IPAddr.new ip
|
|
195
|
+
code = (seek_record_v6(ipaddr.to_i) - COUNTRY_BEGIN)
|
|
196
|
+
else
|
|
186
197
|
throw "Invalid GeoIP database type, can't look up Country by IP"
|
|
187
198
|
end
|
|
188
199
|
|
|
189
|
-
code = (seek_record(ipnum) - COUNTRY_BEGIN)
|
|
190
|
-
|
|
191
200
|
Country.new(
|
|
192
201
|
hostname, # Requested hostname
|
|
193
202
|
ip, # Ip address as dotted quad
|
|
@@ -223,16 +232,18 @@ class GeoIP
|
|
|
223
232
|
def city(hostname)
|
|
224
233
|
ip = lookup_ip(hostname)
|
|
225
234
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
235
|
+
if (@database_type == GEOIP_CITY_EDITION_REV0 ||
|
|
236
|
+
@database_type == GEOIP_CITY_EDITION_REV1)
|
|
237
|
+
# Convert numeric IP address to an integer
|
|
238
|
+
ipnum = iptonum(ip)
|
|
239
|
+
pos = seek_record(ipnum)
|
|
240
|
+
elsif (@database_type == GEOIP_CITY_EDITION_REV1_V6)
|
|
241
|
+
ipaddr = IPAddr.new ip
|
|
242
|
+
pos = seek_record_v6(ipaddr.to_i)
|
|
243
|
+
else
|
|
231
244
|
throw "Invalid GeoIP database type, can't look up City by IP"
|
|
232
245
|
end
|
|
233
246
|
|
|
234
|
-
pos = seek_record(ipnum)
|
|
235
|
-
|
|
236
247
|
# This next statement was added to MaxMind's C version after it was
|
|
237
248
|
# rewritten in Ruby. It prevents unassigned IP addresses from returning
|
|
238
249
|
# bogus data. There was concern over whether the changes to an
|
|
@@ -361,6 +372,7 @@ class GeoIP
|
|
|
361
372
|
@database_segments = [STATE_BEGIN_REV1]
|
|
362
373
|
elsif (@database_type == GEOIP_CITY_EDITION_REV0 ||
|
|
363
374
|
@database_type == GEOIP_CITY_EDITION_REV1 ||
|
|
375
|
+
@database_type == GEOIP_CITY_EDITION_REV1_V6 ||
|
|
364
376
|
@database_type == GEOIP_ORG_EDITION ||
|
|
365
377
|
@database_type == GEOIP_ISP_EDITION ||
|
|
366
378
|
@database_type == GEOIP_ASNUM_EDITION)
|
|
@@ -384,6 +396,7 @@ class GeoIP
|
|
|
384
396
|
|
|
385
397
|
if (@database_type == GEOIP_COUNTRY_EDITION ||
|
|
386
398
|
@database_type == GEOIP_PROXY_EDITION ||
|
|
399
|
+
@database_type == GEOIP_COUNTRY_EDITION_V6 ||
|
|
387
400
|
@database_type == GEOIP_NETSPEED_EDITION)
|
|
388
401
|
@database_segments = [COUNTRY_BEGIN]
|
|
389
402
|
end
|
|
@@ -487,9 +500,11 @@ class GeoIP
|
|
|
487
500
|
end
|
|
488
501
|
|
|
489
502
|
def lookup_ip(ip_or_hostname) # :nodoc:
|
|
490
|
-
|
|
503
|
+
if !ip_or_hostname.kind_of?(String) or ip_or_hostname =~ /^[0-9.]+$/
|
|
504
|
+
return ip_or_hostname
|
|
505
|
+
end
|
|
491
506
|
|
|
492
|
-
# Lookup IP address, we were given a name
|
|
507
|
+
# Lookup IP address, we were given a name or IPv6 address
|
|
493
508
|
ip = IPSocket.getaddress(ip_or_hostname)
|
|
494
509
|
ip = '0.0.0.0' if ip == '::1'
|
|
495
510
|
ip
|
|
@@ -528,6 +543,29 @@ class GeoIP
|
|
|
528
543
|
end
|
|
529
544
|
end
|
|
530
545
|
|
|
546
|
+
def seek_record_v6(ipnum)
|
|
547
|
+
|
|
548
|
+
# Binary search in the file.
|
|
549
|
+
# Records are pairs of little-endian integers, each of @record_length.
|
|
550
|
+
offset = 0
|
|
551
|
+
mask = 1 << 127
|
|
552
|
+
|
|
553
|
+
127.downto(0) do |depth|
|
|
554
|
+
off = (@record_length * 2 * offset)
|
|
555
|
+
buf = atomic_read(@record_length * 2, off)
|
|
556
|
+
|
|
557
|
+
buf.slice!(0...@record_length) if ((ipnum & mask) != 0)
|
|
558
|
+
offset = le_to_ui(buf[0...@record_length].unpack("C*"))
|
|
559
|
+
|
|
560
|
+
if (offset >= @database_segments[0])
|
|
561
|
+
return offset
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
mask >>= 1
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
end
|
|
568
|
+
|
|
531
569
|
# Convert a big-endian array of numeric bytes to unsigned int.
|
|
532
570
|
#
|
|
533
571
|
# 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.1
|
|
4
|
+
version: 1.2.1
|
|
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-12-18 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
|