geoip 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/geoip.rb +73 -33
- metadata +3 -3
data/lib/geoip.rb
CHANGED
@@ -164,8 +164,7 @@ class GeoIP
|
|
164
164
|
"AS","AS","OC","AS","AF","OC","AS","AS","SA","OC","AS","AF","EU","AF",
|
165
165
|
"OC","NA","SA","AS","EU","SA","SA","SA","SA","AS","OC","OC","OC","AS",
|
166
166
|
"AF","EU","AF","AF","AF","AF"]
|
167
|
-
|
168
|
-
private
|
167
|
+
public
|
169
168
|
# Edition enumeration:
|
170
169
|
(GEOIP_COUNTRY_EDITION,
|
171
170
|
GEOIP_CITY_EDITION_REV1,
|
@@ -178,6 +177,7 @@ class GeoIP
|
|
178
177
|
GEOIP_ASNUM_EDITION,
|
179
178
|
GEOIP_NETSPEED_EDITION,
|
180
179
|
) = *1..10
|
180
|
+
private
|
181
181
|
|
182
182
|
COUNTRY_BEGIN = 16776960
|
183
183
|
STATE_BEGIN_REV0 = 16700000
|
@@ -195,6 +195,7 @@ class GeoIP
|
|
195
195
|
SEGMENT_RECORD_LENGTH = 3
|
196
196
|
|
197
197
|
public
|
198
|
+
attr_reader :databaseType
|
198
199
|
# Open the GeoIP database and determine the file format version
|
199
200
|
#
|
200
201
|
# +filename+ is a String holding the path to the GeoIP.dat file
|
@@ -300,51 +301,57 @@ class GeoIP
|
|
300
301
|
# * The latitude
|
301
302
|
# * The longitude
|
302
303
|
# * The dma_code and area_code, if available (REV1 City database)
|
303
|
-
|
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
|
304
|
+
private
|
309
305
|
|
310
|
-
|
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);
|
306
|
+
def read_city(pos, hostname = '', ip = '')
|
317
307
|
@file.seek(pos + (2*@record_length-1) * @databaseSegments[0])
|
318
|
-
|
308
|
+
return nil if((record = @file.read(FULL_RECORD_LENGTH)).nil?)
|
319
309
|
|
320
310
|
# The country code is the first byte:
|
321
311
|
code = record[0]
|
322
312
|
record = record[1..-1]
|
313
|
+
@iter_pos += 1 unless @iter_pos.nil?
|
323
314
|
|
315
|
+
spl = record.split("\x00", 4)
|
324
316
|
# Get the region:
|
325
|
-
|
326
|
-
|
317
|
+
region = spl[0]
|
318
|
+
@iter_pos += (region.size + 1) unless @iter_pos.nil?
|
327
319
|
|
328
320
|
# Get the city:
|
329
|
-
|
330
|
-
|
321
|
+
city = spl[1]
|
322
|
+
@iter_pos += (city.size + 1) unless @iter_pos.nil?
|
331
323
|
|
332
324
|
# Get the postal code:
|
333
|
-
|
334
|
-
|
325
|
+
postal_code = spl[2]
|
326
|
+
@iter_pos += (postal_code.size + 1) unless @iter_pos.nil?
|
335
327
|
|
328
|
+
record = spl[3]
|
336
329
|
# Get the latitude/longitude:
|
337
|
-
|
338
|
-
|
330
|
+
if(record && record[0,3]) then
|
331
|
+
latitude = le_to_ui(record[0,3].unpack('C*')) / 10000.0 - 180
|
332
|
+
record = record[3..-1]
|
333
|
+
@iter_pos += 3 unless @iter_pos.nil?
|
334
|
+
else
|
335
|
+
latitude = ''
|
336
|
+
end
|
337
|
+
if(record && record[0,3]) then
|
338
|
+
longitude = le_to_ui(record[0,3].unpack('C*')) / 10000.0 - 180
|
339
|
+
record = record[3..-1]
|
340
|
+
@iter_pos += 3 unless @iter_pos.nil?
|
341
|
+
else
|
342
|
+
longitude = ''
|
343
|
+
end
|
339
344
|
|
340
|
-
record = record[6..-1]
|
341
345
|
us_area_codes = []
|
346
|
+
if(record && record[0,3]) then
|
342
347
|
if (@databaseType == GEOIP_CITY_EDITION_REV1 &&
|
343
348
|
CountryCode[code] == "US") # UNTESTED
|
344
|
-
|
345
|
-
|
346
|
-
|
349
|
+
dmaarea_combo = le_to_ui(record[0,3].unpack('C*'))
|
350
|
+
dma_code = dmaarea_combo / 1000;
|
351
|
+
area_code = dmaarea_combo % 1000;
|
347
352
|
us_area_codes = [ dma_code, area_code ]
|
353
|
+
@iter_pos += 3 unless @iter_pos.nil?
|
354
|
+
end
|
348
355
|
end
|
349
356
|
|
350
357
|
[ hostname, # Requested hostname
|
@@ -359,7 +366,39 @@ class GeoIP
|
|
359
366
|
latitude,
|
360
367
|
longitude,
|
361
368
|
] + us_area_codes
|
369
|
+
end
|
370
|
+
public
|
371
|
+
def city(hostname)
|
372
|
+
ip = hostname
|
373
|
+
if ip.kind_of?(String) && ip !~ /^[0-9.]*$/
|
374
|
+
# Lookup IP address, we were given a name
|
375
|
+
ip = IPSocket.getaddress(hostname)
|
376
|
+
end
|
377
|
+
|
378
|
+
# Convert numeric IP address to an integer
|
379
|
+
ipnum = iptonum(ip)
|
380
|
+
if (@databaseType != GEOIP_CITY_EDITION_REV0 &&
|
381
|
+
@databaseType != GEOIP_CITY_EDITION_REV1)
|
382
|
+
throw "Invalid GeoIP database type, can't look up City by IP"
|
383
|
+
end
|
384
|
+
pos = seek_record(ipnum);
|
385
|
+
read_city(pos, hostname, ip)
|
386
|
+
end
|
362
387
|
|
388
|
+
def each
|
389
|
+
if (@databaseType != GEOIP_CITY_EDITION_REV0 &&
|
390
|
+
@databaseType != GEOIP_CITY_EDITION_REV1)
|
391
|
+
throw "Invalid GeoIP database type, can't iterate thru non-City database"
|
392
|
+
end
|
393
|
+
|
394
|
+
@iter_pos = @databaseSegments[0] + 1
|
395
|
+
num = 0
|
396
|
+
until((rec = read_city(@iter_pos)).nil?)
|
397
|
+
yield(rec)
|
398
|
+
print "#{num}: #{@iter_pos}\n" if((num += 1) % 1000 == 0)
|
399
|
+
end
|
400
|
+
@iter_pos = nil
|
401
|
+
self
|
363
402
|
end
|
364
403
|
|
365
404
|
private
|
@@ -375,21 +414,21 @@ class GeoIP
|
|
375
414
|
# Binary search in the file.
|
376
415
|
# Records are pairs of little-endian integers, each of @record_length.
|
377
416
|
offset = 0
|
378
|
-
|
417
|
+
mask = 0x80000000
|
379
418
|
31.downto(0) { |depth|
|
380
419
|
@file.seek(@record_length * 2 * offset);
|
381
|
-
|
420
|
+
buf = @file.read(@record_length * 2);
|
382
421
|
buf.slice!(0...@record_length) if ((ipnum & mask) != 0)
|
383
422
|
offset = le_to_ui(buf[0...@record_length].unpack("C*"))
|
384
423
|
return offset if (offset >= @databaseSegments[0])
|
385
|
-
|
424
|
+
mask >>= 1
|
386
425
|
}
|
387
426
|
end
|
388
427
|
|
389
428
|
# Convert a big-endian array of numeric bytes to unsigned int
|
390
429
|
def be_to_ui(s)
|
391
430
|
s.inject(0) { |m, o|
|
392
|
-
|
431
|
+
(m << 8) + o.to_i
|
393
432
|
}
|
394
433
|
end
|
395
434
|
|
@@ -402,7 +441,8 @@ end
|
|
402
441
|
if $0 == __FILE__
|
403
442
|
g = GeoIP.new('/usr/share/GeoIP/GeoIP.dat');
|
404
443
|
|
444
|
+
req = ([GeoIP::GEOIP_CITY_EDITION_REV1, GeoIP::GEOIP_CITY_EDITION_REV0].include?(g.databaseType)) ? :city : :country
|
405
445
|
ARGV.each { |a|
|
406
|
-
|
446
|
+
p g.send(req, a)
|
407
447
|
}
|
408
448
|
end
|
metadata
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.8.
|
2
|
+
rubygems_version: 0.8.10
|
3
3
|
specification_version: 1
|
4
4
|
name: geoip
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date:
|
6
|
+
version: 0.3.0
|
7
|
+
date: 2006-09-25
|
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
10
|
www.maxmind.com only contains country information. This library supports that
|