geoip 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/geoip.rb +86 -4
- metadata +6 -6
data/lib/geoip.rb
CHANGED
@@ -189,6 +189,7 @@ class GeoIP
|
|
189
189
|
CANADA_OFFSET = 677
|
190
190
|
WORLD_OFFSET = 1353
|
191
191
|
FIPS_RANGE = 360
|
192
|
+
FULL_RECORD_LENGTH = 50
|
192
193
|
|
193
194
|
STANDARD_RECORD_LENGTH = 3
|
194
195
|
SEGMENT_RECORD_LENGTH = 3
|
@@ -203,13 +204,15 @@ class GeoIP
|
|
203
204
|
@databaseType = GEOIP_COUNTRY_EDITION
|
204
205
|
@record_length = STANDARD_RECORD_LENGTH
|
205
206
|
@file = File.open(filename, 'rb')
|
206
|
-
@file.seek(-
|
207
|
-
|
207
|
+
@file.seek(-3, IO::SEEK_END)
|
208
|
+
0.upto(STRUCTURE_INFO_MAX_SIZE-1) { |i|
|
208
209
|
if @file.read(3) == "\xFF\xFF\xFF"
|
209
210
|
@databaseType = @file.getc
|
210
211
|
@databaseType -= 105 if @databaseType >= 106
|
211
212
|
|
212
|
-
|
213
|
+
if (@databaseType != GEOIP_CITY_EDITION_REV0)
|
214
|
+
puts "Old database file type #{@databaseType}, untested"
|
215
|
+
end
|
213
216
|
|
214
217
|
if (@databaseType == GEOIP_REGION_EDITION_REV0)
|
215
218
|
# Region Edition, pre June 2003
|
@@ -232,9 +235,10 @@ class GeoIP
|
|
232
235
|
@record_length = 4
|
233
236
|
end
|
234
237
|
end
|
238
|
+
break
|
235
239
|
|
236
240
|
else
|
237
|
-
@file.seek(-
|
241
|
+
@file.seek(-4, IO::SEEK_CUR)
|
238
242
|
end
|
239
243
|
}
|
240
244
|
if (@databaseType == GEOIP_COUNTRY_EDITION ||
|
@@ -257,6 +261,11 @@ class GeoIP
|
|
257
261
|
# * The two-character continent code
|
258
262
|
#
|
259
263
|
def country(hostname)
|
264
|
+
if (@databaseType == GEOIP_CITY_EDITION_REV0 ||
|
265
|
+
@databaseType == GEOIP_CITY_EDITION_REV1)
|
266
|
+
return city(hostname)
|
267
|
+
end
|
268
|
+
|
260
269
|
ip = hostname
|
261
270
|
if ip.kind_of?(String) && ip !~ /^[0-9.]*$/
|
262
271
|
# Lookup IP address, we were given a name
|
@@ -280,6 +289,79 @@ class GeoIP
|
|
280
289
|
CountryContinent[code] ] # Continent code.
|
281
290
|
end
|
282
291
|
|
292
|
+
# Search the GeoIP database for the specified host, returning city info
|
293
|
+
#
|
294
|
+
# +hostname+ is a String holding the host's DNS name or numeric IP address
|
295
|
+
# Return an array of eleven or thirteen elements:
|
296
|
+
# * All elements from the country query
|
297
|
+
# * The region (state or territory) name
|
298
|
+
# * The city name
|
299
|
+
# * The postal code (zipcode)
|
300
|
+
# * The latitude
|
301
|
+
# * The longitude
|
302
|
+
# * The dma_code and area_code, if available (REV1 City database)
|
303
|
+
def city(hostname)
|
304
|
+
ip = hostname
|
305
|
+
if ip.kind_of?(String) && ip !~ /^[0-9.]*$/
|
306
|
+
# Lookup IP address, we were given a name
|
307
|
+
ip = IPSocket.getaddress(hostname)
|
308
|
+
end
|
309
|
+
|
310
|
+
# Convert numeric IP address to an integer
|
311
|
+
ipnum = iptonum(ip)
|
312
|
+
if (@databaseType != GEOIP_CITY_EDITION_REV0 &&
|
313
|
+
@databaseType != GEOIP_CITY_EDITION_REV1)
|
314
|
+
throw "Invalid GeoIP database type, can't look up City by IP"
|
315
|
+
end
|
316
|
+
pos = seek_record(ipnum);
|
317
|
+
@file.seek(pos + (2*@record_length-1) * @databaseSegments[0])
|
318
|
+
record = @file.read(FULL_RECORD_LENGTH)
|
319
|
+
|
320
|
+
# The country code is the first byte:
|
321
|
+
code = record[0]
|
322
|
+
record = record[1..-1]
|
323
|
+
|
324
|
+
# Get the region:
|
325
|
+
region = record.sub(/\x00.*/, "")
|
326
|
+
record.sub!(/[^\x00]*\x00/, '')
|
327
|
+
|
328
|
+
# Get the city:
|
329
|
+
city = record.sub(/\x00.*/, "")
|
330
|
+
record.sub!(/[^\x00]*\x00/, '')
|
331
|
+
|
332
|
+
# Get the postal code:
|
333
|
+
postal_code = record.sub(/\x00.*/, "")
|
334
|
+
record.sub!(/[^\x00]*\x00/, '')
|
335
|
+
|
336
|
+
# Get the latitude/longitude:
|
337
|
+
latitude = le_to_ui(record[0,3].unpack("C*"))/10000.0 - 180
|
338
|
+
longitude = le_to_ui(record[3,3].unpack("C*"))/10000.0 - 180
|
339
|
+
|
340
|
+
record = record[6..-1]
|
341
|
+
us_area_codes = []
|
342
|
+
if (@databaseType == GEOIP_CITY_EDITION_REV1 &&
|
343
|
+
CountryCode[code] == "US") # UNTESTED
|
344
|
+
dmaarea_combo = le_to_ui(record[0,3].unpack("C*"))
|
345
|
+
dma_code = dmaarea_combo/1000;
|
346
|
+
area_code = dmaarea_combo%1000;
|
347
|
+
us_area_codes = [ dma_code, area_code ]
|
348
|
+
end
|
349
|
+
|
350
|
+
[ hostname, # Requested hostname
|
351
|
+
ip, # Ip address as dotted quad
|
352
|
+
CountryCode[code], # ISO3166-1 code
|
353
|
+
CountryCode3[code], # ISO3166-2 code
|
354
|
+
CountryName[code], # Country name, per IS03166
|
355
|
+
CountryContinent[code], # Continent code.
|
356
|
+
region, # Region name
|
357
|
+
city, # City name
|
358
|
+
postal_code, # Postal code
|
359
|
+
latitude,
|
360
|
+
longitude,
|
361
|
+
] + us_area_codes
|
362
|
+
|
363
|
+
end
|
364
|
+
|
283
365
|
private
|
284
366
|
def iptonum(ip) # Convert numeric IP address to integer
|
285
367
|
if ip.kind_of?(String) &&
|
metadata
CHANGED
@@ -3,13 +3,13 @@ rubygems_version: 0.8.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: geoip
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2005-
|
6
|
+
version: 0.2.0
|
7
|
+
date: 2005-04-27
|
8
8
|
summary: "GeoIP looks up a GeoIP database to provide geographical data for an IP address
|
9
9
|
or Internet hostname. The free version of the GeoIP database available from
|
10
|
-
www.maxmind.com only contains country information
|
11
|
-
|
12
|
-
codes at the end of the hosts' domain names."
|
10
|
+
www.maxmind.com only contains country information. This library supports that
|
11
|
+
and the GeoIPCity file (both revisions). The data is much more reliable than
|
12
|
+
using the country codes at the end of the hosts' domain names."
|
13
13
|
require_paths:
|
14
14
|
- lib
|
15
15
|
email: cjh@polyplex.org
|
@@ -40,5 +40,5 @@ extra_rdoc_files: []
|
|
40
40
|
executables: []
|
41
41
|
extensions: []
|
42
42
|
requirements:
|
43
|
-
- The free GeoIP database from www.maxmind.com
|
43
|
+
- The free GeoIP database or a GeoIP city database from www.maxmind.com
|
44
44
|
dependencies: []
|