geoip 0.2.0 → 0.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/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
|