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.
Files changed (6) hide show
  1. data/History.rdoc +4 -0
  2. data/README.rdoc +26 -14
  3. data/Rakefile +2 -2
  4. data/geoip.gemspec +4 -4
  5. data/lib/geoip.rb +58 -20
  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"]
@@ -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
- License as published by the Free Software Foundation; either
81
- version 2.1 of the License, or (at your option) any later version.
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 = "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,
@@ -31,7 +31,7 @@ Rake::TestTask.new(:test) do |test|
31
31
  end
32
32
  task :default => :test
33
33
 
34
- require 'rake/rdoctask'
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.2"
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-01-26"
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 = ["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.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
- # Convert numeric IP address to an integer
181
- ipnum = iptonum(ip)
182
-
183
- if (@database_type != GEOIP_COUNTRY_EDITION &&
184
- @database_type != GEOIP_PROXY_EDITION &&
185
- @database_type != GEOIP_NETSPEED_EDITION)
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
- # 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)
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
- return ip_or_hostname unless (ip_or_hostname.kind_of?(String) && ip_or_hostname !~ /^[0-9.]+$/)
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.2
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-01-26 00:00:00.000000000 Z
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
- - 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