geoip 1.1.2 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. data/History.rdoc +4 -0
  2. data/README.rdoc +20 -11
  3. data/Rakefile +1 -1
  4. data/geoip.gemspec +4 -4
  5. data/lib/geoip.rb +50 -16
  6. metadata +4 -4
data/History.rdoc CHANGED
@@ -1,3 +1,7 @@
1
+ == 1.2.0 2012-10-17
2
+
3
+ * Added support for GeoLiteCityv6 IPv6 database type
4
+
1
5
  == 0.8.1 2009-06-04
2
6
 
3
7
  * Added GeoIP#close method to close the file descriptor
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
- Returned values are the requested hostname, the IP address as a dotted quad,
29
- Maxmind's country code, the ISO3166-1 alpha-2 country code, the ISO3166-2 alpha-3
30
- country code, the ISO3166 country name, and the continent code.
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
- Returned values are the requested hostname, the IP address as a dotted quad,
44
- the ISO3166-1 alpha-2 country code, the ISO3166-2 alpha-3 country code, the
45
- ISO3166 country name, the continent code, the region (state or territory) name,
46
- city name, postal_code/zipcode, latitude, longitude, USA DMA code, USA area code,
47
- timezone name.
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
- Result arrays from both city and country have mixed-in accessor methods as appropriate:
50
- request, ip, country_code, country_code2, country_code3, country_name, continent_code,
51
- region_name, city_name, postal_code, latitude, longitude, dma_code, area_code, timezone
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 = "MIT"
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.1.2"
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-01-26"
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 = ["MIT"]
43
+ s.licenses = ["GPL"]
44
44
  s.require_paths = ["lib"]
45
- s.rubygems_version = "1.8.10"
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.2"
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
- # Convert numeric IP address to an integer
227
- ipnum = iptonum(ip)
228
-
229
- if (@database_type != GEOIP_CITY_EDITION_REV0 &&
230
- @database_type != GEOIP_CITY_EDITION_REV1)
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
- return ip_or_hostname unless (ip_or_hostname.kind_of?(String) && ip_or_hostname !~ /^[0-9.]+$/)
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.1.2
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-01-26 00:00:00.000000000 Z
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
- - MIT
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.10
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