geoip 1.2.0 → 1.3.0

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/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.2.0"
8
+ s.version = "1.3.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-10-16"
12
+ s.date = "2013-08-13"
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"]
@@ -26,6 +26,7 @@ Gem::Specification.new do |s|
26
26
  "data/geoip/country_code3.yml",
27
27
  "data/geoip/country_continent.yml",
28
28
  "data/geoip/country_name.yml",
29
+ "data/geoip/region.yml",
29
30
  "data/geoip/time_zone.yml",
30
31
  "geoip.gemspec",
31
32
  "lib/geoip.rb",
@@ -40,7 +41,7 @@ Gem::Specification.new do |s|
40
41
  "website/template.rhtml"
41
42
  ]
42
43
  s.homepage = "http://github.com/cjheath/geoip"
43
- s.licenses = ["GPL"]
44
+ s.licenses = ["LGPL"]
44
45
  s.require_paths = ["lib"]
45
46
  s.rubygems_version = "1.8.24"
46
47
  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."
data/lib/geoip.rb CHANGED
@@ -8,19 +8,18 @@
8
8
  # Derived from the C version, Copyright (C) 2003 MaxMind LLC
9
9
  #
10
10
  # This library is free software; you can redistribute it and/or
11
- # modify it under the terms of the GNU General Public
11
+ # modify it under the terms of the GNU Lesser General Public
12
12
  # License as published by the Free Software Foundation; either
13
13
  # version 2.1 of the License, or (at your option) any later version.
14
14
  #
15
15
  # This library is distributed in the hope that it will be useful,
16
16
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
17
17
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
- # General Public License for more details.
18
+ # Lesser General Public License for more details.
19
19
  #
20
- # You should have received a copy of the GNU General Public
20
+ # You should have received a copy of the GNU Lesser General Public
21
21
  # License along with this library; if not, write to the Free Software
22
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
- #
22
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24
23
  # = SYNOPSIS
25
24
  #
26
25
  # require 'geoip'
@@ -59,7 +58,7 @@ require 'yaml'
59
58
  class GeoIP
60
59
 
61
60
  # The GeoIP GEM version number
62
- VERSION = "1.2.0"
61
+ VERSION = "1.3.0"
63
62
 
64
63
  # The +data/+ directory for geoip
65
64
  DATA_DIR = File.expand_path(File.join(File.dirname(__FILE__),'..','data','geoip'))
@@ -79,6 +78,9 @@ class GeoIP
79
78
  # ordered by GeoIP ID
80
79
  CountryContinent = YAML.load_file(File.join(DATA_DIR,'country_continent.yml'))
81
80
 
81
+ # Load a hash of region names by region code
82
+ RegionName = YAML.load_file(File.join(DATA_DIR,'region.yml'))
83
+
82
84
  # Hash of the timezone codes mapped to timezone name, per zoneinfo
83
85
  TimeZone = YAML.load_file(File.join(DATA_DIR,'time_zone.yml'))
84
86
 
@@ -92,6 +94,7 @@ class GeoIP
92
94
  GEOIP_PROXY_EDITION = 8
93
95
  GEOIP_ASNUM_EDITION = 9
94
96
  GEOIP_NETSPEED_EDITION = 10
97
+ GEOIP_COUNTRY_EDITION_V6 = 12
95
98
  GEOIP_CITY_EDITION_REV1_V6 = 30
96
99
 
97
100
  COUNTRY_BEGIN = 16776960 #:nodoc:
@@ -118,13 +121,27 @@ class GeoIP
118
121
 
119
122
  end
120
123
 
124
+ class Region < Struct.new(:request, :ip, :country_code2, :country_code3, :country_name, :continent_code,
125
+ :region_code, :region_name, :timezone)
126
+
127
+ def to_hash
128
+ Hash[each_pair.to_a]
129
+ end
130
+
131
+ end
132
+
133
+ # Warning: for historical reasons the region code is mis-named region_name here
121
134
  class City < Struct.new(:request, :ip, :country_code2, :country_code3, :country_name, :continent_code,
122
- :region_name, :city_name, :postal_code, :latitude, :longitude, :dma_code, :area_code, :timezone)
135
+ :region_name, :city_name, :postal_code, :latitude, :longitude, :dma_code, :area_code, :timezone, :real_region_name)
123
136
 
124
137
  def to_hash
125
138
  Hash[each_pair.to_a]
126
139
  end
127
140
 
141
+ def region_code
142
+ self.region_name
143
+ end
144
+
128
145
  end
129
146
 
130
147
  class ASN < Struct.new(:number, :asn)
@@ -136,6 +153,9 @@ class GeoIP
136
153
  # The Edition number that identifies which kind of database you've opened
137
154
  attr_reader :database_type
138
155
 
156
+ # An IP that is used instead of local IPs
157
+ attr_accessor :local_ip_alias
158
+
139
159
  alias databaseType database_type
140
160
 
141
161
  # Open the GeoIP database and determine the file format version.
@@ -182,17 +202,24 @@ class GeoIP
182
202
  return city(hostname)
183
203
  end
184
204
 
185
- if (@database_type != GEOIP_COUNTRY_EDITION &&
186
- @database_type != GEOIP_PROXY_EDITION &&
187
- @database_type != GEOIP_NETSPEED_EDITION)
188
- throw "Invalid GeoIP database type, can't look up Country by IP"
205
+ if (@database_type == GEOIP_REGION_EDITION_REV0 ||
206
+ @database_type == GEOIP_REGION_EDITION_REV1)
207
+ return region(hostname)
189
208
  end
190
209
 
191
210
  ip = lookup_ip(hostname)
192
-
193
- ipnum = iptonum(ip) # Convert numeric IP address to an integer
194
-
195
- code = (seek_record(ipnum) - COUNTRY_BEGIN)
211
+ if (@database_type == GEOIP_COUNTRY_EDITION ||
212
+ @database_type == GEOIP_PROXY_EDITION ||
213
+ @database_type == GEOIP_NETSPEED_EDITION)
214
+ # Convert numeric IP address to an integer
215
+ ipnum = iptonum(ip)
216
+ code = (seek_record(ipnum) - COUNTRY_BEGIN)
217
+ elsif @database_type == GEOIP_COUNTRY_EDITION_V6
218
+ ipaddr = IPAddr.new ip
219
+ code = (seek_record_v6(ipaddr.to_i) - COUNTRY_BEGIN)
220
+ else
221
+ throw "Invalid GeoIP database type, can't look up Country by IP"
222
+ end
196
223
 
197
224
  Country.new(
198
225
  hostname, # Requested hostname
@@ -205,6 +232,42 @@ class GeoIP
205
232
  )
206
233
  end
207
234
 
235
+ # Search the GeoIP database for the specified host, retuning region info.
236
+ #
237
+ # +hostname+ is a String holding the hosts's DNS name or numeric IP
238
+ # address.
239
+ #
240
+ # Returns a Region object with the nine elements:
241
+ # * The host or IP address string as requested
242
+ # * The IP address string after looking up the host
243
+ # * The two-character country code (ISO 3166-1 alpha-2)
244
+ # * The three-character country code (ISO 3166-2 alpha-3)
245
+ # * The ISO 3166 English-language name of the country
246
+ # * The two-character continent code
247
+ # * The region name (state or territory)
248
+ # * The timezone name, if known
249
+ #
250
+ def region(hostname)
251
+ if (@database_type == GEOIP_CITY_EDITION_REV0 ||
252
+ @database_type == GEOIP_CITY_EDITION_REV1 ||
253
+ @database_type == GEOIP_CITY_EDITION_REV1_V6)
254
+ return city(hostname)
255
+ end
256
+
257
+ if (@database_type == GEOIP_REGION_EDITION_REV0 ||
258
+ @database_type == GEOIP_REGION_EDITION_REV1)
259
+ ip = lookup_ip(hostname)
260
+ ipnum = iptonum(ip)
261
+ pos = seek_record(ipnum)
262
+ else
263
+ throw "Invalid GeoIP database type, can't look up Region by IP"
264
+ end
265
+
266
+ unless pos == @database_segments[0]
267
+ read_region(pos, hostname, ip)
268
+ end
269
+ end
270
+
208
271
  # Search the GeoIP database for the specified host, returning city info.
209
272
  #
210
273
  # +hostname+ is a String holding the host's DNS name or numeric IP
@@ -393,11 +456,57 @@ class GeoIP
393
456
 
394
457
  if (@database_type == GEOIP_COUNTRY_EDITION ||
395
458
  @database_type == GEOIP_PROXY_EDITION ||
459
+ @database_type == GEOIP_COUNTRY_EDITION_V6 ||
396
460
  @database_type == GEOIP_NETSPEED_EDITION)
397
461
  @database_segments = [COUNTRY_BEGIN]
398
462
  end
399
463
  end
400
464
 
465
+ def read_region(pos, hostname = '', ip = '') #:nodoc:
466
+ if (@database_type == GEOIP_REGION_EDITION_REV0)
467
+ pos -= STATE_BEGIN_REV0
468
+ if (pos >= 1000)
469
+ code = 225
470
+ region_code = ((pos - 1000) / 26 + 65).chr + ((pos - 1000) % 26 + 65).chr
471
+ else
472
+ code = pos
473
+ region_code = ''
474
+ end
475
+ elsif (@database_type == GEOIP_REGION_EDITION_REV1)
476
+ pos -= STATE_BEGIN_REV1
477
+ if (pos < US_OFFSET)
478
+ code = 0
479
+ region_code = ''
480
+ elsif (pos < CANADA_OFFSET)
481
+ code = 225
482
+ region_code = ((pos - US_OFFSET) / 26 + 65).chr + ((pos - US_OFFSET) % 26 + 65).chr
483
+ elsif (pos < WORLD_OFFSET)
484
+ code = 38
485
+ region_code = ((pos - CANADA_OFFSET) / 26 + 65).chr + ((pos - CANADA_OFFSET) % 26 + 65).chr
486
+ else
487
+ code = (pos - WORLD_OFFSET) / FIPS_RANGE
488
+ region_code = ''
489
+ end
490
+ end
491
+
492
+ Region.new(
493
+ hostname,
494
+ ip,
495
+ CountryCode[code], # ISO3166-1 alpha-2 code
496
+ CountryCode3[code], # ISO3166-2 alpha-3 code
497
+ CountryName[code], # Country name, per ISO 3166
498
+ CountryContinent[code], # Continent code.
499
+ region_code, # Unfortunately this is called region_name in the City structure
500
+ lookup_region_name(CountryCode[code], region_code),
501
+ (TimeZone["#{CountryCode[code]}#{region_code}"] || TimeZone["#{CountryCode[code]}"])
502
+ )
503
+ end
504
+
505
+ def lookup_region_name(country_iso2, region_code)
506
+ country_regions = RegionName[country_iso2]
507
+ country_regions && country_regions[region_code]
508
+ end
509
+
401
510
  # Search the GeoIP database for the specified host, returning city info.
402
511
  #
403
512
  # +hostname+ is a String holding the host's DNS name or numeric
@@ -427,9 +536,9 @@ class GeoIP
427
536
  @iter_pos += 1 unless @iter_pos.nil?
428
537
 
429
538
  spl = record.split("\x00", 4)
430
- # Get the region:
431
- region = spl[0]
432
- @iter_pos += (region.size + 1) unless @iter_pos.nil?
539
+ # Get the region code:
540
+ region_code = spl[0]
541
+ @iter_pos += (region_code.size + 1) unless @iter_pos.nil?
433
542
 
434
543
  # Get the city:
435
544
  city = spl[1]
@@ -439,7 +548,7 @@ class GeoIP
439
548
 
440
549
  # Get the postal code:
441
550
  postal_code = spl[2]
442
- @iter_pos += (postal_code.size + 1) unless @iter_pos.nil?
551
+ @iter_pos += (postal_code.size + 1) unless @iter_pos.nil? || postal_code.nil?
443
552
 
444
553
  record = spl[3]
445
554
 
@@ -484,18 +593,23 @@ class GeoIP
484
593
  CountryCode3[code], # ISO3166-2 code
485
594
  CountryName[code], # Country name, per IS03166
486
595
  CountryContinent[code], # Continent code.
487
- region, # Region name
596
+ region_code, # Region code (called region_name, unfortunately)
488
597
  city, # City name
489
598
  postal_code, # Postal code
490
599
  latitude,
491
600
  longitude,
492
601
  dma_code,
493
602
  area_code,
494
- (TimeZone["#{CountryCode[code]}#{region}"] || TimeZone["#{CountryCode[code]}"])
603
+ (TimeZone["#{CountryCode[code]}#{region_code}"] || TimeZone["#{CountryCode[code]}"]),
604
+ lookup_region_name(CountryCode[code], region_code) # Real region name
495
605
  )
496
606
  end
497
607
 
498
608
  def lookup_ip(ip_or_hostname) # :nodoc:
609
+ if is_local?(ip_or_hostname) && @local_ip_alias
610
+ ip_or_hostname = @local_ip_alias
611
+ end
612
+
499
613
  if !ip_or_hostname.kind_of?(String) or ip_or_hostname =~ /^[0-9.]+$/
500
614
  return ip_or_hostname
501
615
  end
@@ -506,6 +620,10 @@ class GeoIP
506
620
  ip
507
621
  end
508
622
 
623
+ def is_local?(ip_or_hostname) #:nodoc:
624
+ ["127.0.0.1", "localhost", "::1", "0000::1", "0:0:0:0:0:0:0:1"].include? ip_or_hostname
625
+ end
626
+
509
627
  # Convert numeric IP address to Integer.
510
628
  def iptonum(ip) #:nodoc:
511
629
  if (ip.kind_of?(String) &&
data/script/txt2html CHANGED
@@ -2,9 +2,8 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'redcloth'
5
- require 'syntax/convertors/html'
6
5
  require 'erb'
7
- require File.dirname(__FILE__) + '/../lib/geoip.rb'
6
+ require './' + File.dirname(__FILE__) + '/../lib/geoip.rb'
8
7
 
9
8
  version = GeoIP::VERSION
10
9
  download = 'http://rubyforge.org/projects/geoip'
@@ -15,9 +14,9 @@ class Fixnum
15
14
  return 'th' if (10..19).include?(self % 100)
16
15
  # others
17
16
  case self % 10
18
- when 1: return 'st'
19
- when 2: return 'nd'
20
- when 3: return 'rd'
17
+ when 1; return 'st'
18
+ when 2; return 'nd'
19
+ when 3; return 'rd'
21
20
  else return 'th'
22
21
  end
23
22
  end
data/website/index.txt CHANGED
@@ -65,15 +65,15 @@ This version Copyright (C) 2005 Clifford Heath
65
65
  Derived from the C version, Copyright (C) 2003 MaxMind LLC
66
66
 
67
67
  This library is free software; you can redistribute it and/or
68
- modify it under the terms of the GNU General Public
68
+ modify it under the terms of the GNU Lesser General Public
69
69
  License as published by the Free Software Foundation; either
70
70
  version 2.1 of the License, or (at your option) any later version.
71
71
 
72
72
  This library is distributed in the hope that it will be useful,
73
73
  but WITHOUT ANY WARRANTY; without even the implied warranty of
74
74
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
75
- General Public License for more details.
75
+ Lesser General Public License for more details.
76
76
 
77
- You should have received a copy of the GNU General Public
77
+ You should have received a copy of the GNU Lesser General Public
78
78
  License along with this library; if not, write to the Free Software
79
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
79
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
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.2.0
4
+ version: 1.3.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-10-16 00:00:00.000000000 Z
13
+ date: 2013-08-13 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
 
@@ -35,6 +35,7 @@ files:
35
35
  - data/geoip/country_code3.yml
36
36
  - data/geoip/country_continent.yml
37
37
  - data/geoip/country_name.yml
38
+ - data/geoip/region.yml
38
39
  - data/geoip/time_zone.yml
39
40
  - geoip.gemspec
40
41
  - lib/geoip.rb
@@ -49,7 +50,7 @@ files:
49
50
  - website/template.rhtml
50
51
  homepage: http://github.com/cjheath/geoip
51
52
  licenses:
52
- - GPL
53
+ - LGPL
53
54
  post_install_message:
54
55
  rdoc_options: []
55
56
  require_paths: