geoip_multi 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/geoip_multi.rb +144 -0
- metadata +64 -0
data/lib/geoip_multi.rb
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
# Extension to Native Ruby reader for the GeoIP database
|
2
|
+
# Added support for netmask() and range_by_ip()
|
3
|
+
# Created new method to retrieve all available information based on
|
4
|
+
# the various GeoIP database files that are available
|
5
|
+
#
|
6
|
+
# = COPYRIGHT
|
7
|
+
#
|
8
|
+
# This version Copyright (C) 2013 Ryan Harris
|
9
|
+
# Derived from the C version, Copyright (C) 2003 MaxMind LLC
|
10
|
+
#
|
11
|
+
# This library is free software; you can redistribute it and/or
|
12
|
+
# modify it under the terms of the GNU Lesser General Public
|
13
|
+
# License as published by the Free Software Foundation; either
|
14
|
+
# version 2.1 of the License, or (at your option) any later version.
|
15
|
+
#
|
16
|
+
# This library is distributed in the hope that it will be useful,
|
17
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
18
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
19
|
+
# Lesser General Public License for more details.
|
20
|
+
#
|
21
|
+
# You should have received a copy of the GNU Lesser General Public
|
22
|
+
# License along with this library; if not, write to the Free Software
|
23
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
24
|
+
# = SYNOPSIS
|
25
|
+
#
|
26
|
+
# require 'geoip_multi'
|
27
|
+
# GeoIPMulti.new('/usr/share/GeoIP/').lookup('24.24.24.24')
|
28
|
+
#
|
29
|
+
# = DESCRIPTION
|
30
|
+
#
|
31
|
+
# GeoIP searches a GeoIP database for a given host or IP address, and
|
32
|
+
# returns information about the country where the IP address is allocated.
|
33
|
+
#
|
34
|
+
# = PREREQUISITES
|
35
|
+
#
|
36
|
+
# You need at least the free GeoIP.dat, for which the last known download
|
37
|
+
# location is <http://www.maxmind.com/download/geoip/database/GeoIP.dat.gz>
|
38
|
+
# This API requires the file to be decompressed for searching. Other versions
|
39
|
+
# of this database are available for purchase which contain more detailed
|
40
|
+
# information, but this information is not returned by this implementation.
|
41
|
+
# See www.maxmind.com for more information.
|
42
|
+
|
43
|
+
gem 'geoip', '>=1.3.3'
|
44
|
+
require 'geoip'
|
45
|
+
|
46
|
+
class GeoIP
|
47
|
+
@last_netmask=0
|
48
|
+
|
49
|
+
def netmask (ip)
|
50
|
+
seek_netmask(iptonum(ip))
|
51
|
+
@last_netmask
|
52
|
+
end
|
53
|
+
|
54
|
+
def filename
|
55
|
+
@file.path
|
56
|
+
end
|
57
|
+
|
58
|
+
def range_by_ip(ip)
|
59
|
+
ipnum = iptonum(ip)
|
60
|
+
record=seek_netmask(ipnum)
|
61
|
+
mask = 0xffffffff << 32 - @last_netmask
|
62
|
+
left_seek_num = ipnum & mask
|
63
|
+
right_seek_num = left_seek_num + ( 0xffffffff & ~mask )
|
64
|
+
while (left_seek_num !=0 and record == seek_netmask(left_seek_num - 1))
|
65
|
+
leftmask = 0xffffffff << 32 - @last_netmask
|
66
|
+
left_seek_num = (left_seek_num - 1) & leftmask
|
67
|
+
end
|
68
|
+
while (right_seek_num != 0xffffffff and record == seek_netmask(right_seek_num + 1))
|
69
|
+
rightmask = 0xffffffff << 32 - @last_netmask
|
70
|
+
right_seek_num = ( right_seek_num + 1 ) & rightmask
|
71
|
+
right_seek_num += (0xffffffff & ~rightmask)
|
72
|
+
end
|
73
|
+
[numtoip(left_seek_num), numtoip(right_seek_num)]
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def numtoip(ipnum) #:nodoc:
|
79
|
+
IPAddr.new(ipnum, Socket::AF_INET).to_s
|
80
|
+
end
|
81
|
+
|
82
|
+
def seek_netmask(ipnum) #:nodoc:
|
83
|
+
# minor modification of original seek_record() method to include updating @last_netmask
|
84
|
+
offset = 0
|
85
|
+
31.downto(0) do |depth|
|
86
|
+
off = (@record_length * 2 * offset)
|
87
|
+
buf = atomic_read(@record_length * 2, off)
|
88
|
+
buf.slice!(0...@record_length) if ((ipnum & (1 << depth)) != 0)
|
89
|
+
offset = le_to_ui(buf[0...@record_length].unpack("C*"))
|
90
|
+
if (offset >= @database_segments[0])
|
91
|
+
@last_netmask = 32 - depth
|
92
|
+
return offset
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
class GeoIPMulti < GeoIP
|
100
|
+
|
101
|
+
def initialize (*filenames)
|
102
|
+
@geoip_databases=[]
|
103
|
+
filenames=Dir.glob(File.join(File.expand_path($0)[/(.*\/)/],'*.dat')) if filenames.length == 0
|
104
|
+
add_database(filenames)
|
105
|
+
end
|
106
|
+
|
107
|
+
def add_database (*filenames)
|
108
|
+
filenames.flatten!
|
109
|
+
filenames.each do |filename|
|
110
|
+
if File.directory?(filename)
|
111
|
+
Dir.glob(File.join(filename,'*.dat')) {|filename| @geoip_databases << GeoIP.new(filename)}
|
112
|
+
else
|
113
|
+
GeoIP.new(filename)
|
114
|
+
@geoip_databases << GeoIP.new(filename)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def lookup(ip)
|
120
|
+
results ={}
|
121
|
+
@geoip_databases.each do |current_database|
|
122
|
+
case current_database.database_type
|
123
|
+
#IPv4 addresses expected, IPv6 not currently supported, maybe in the future...
|
124
|
+
when GEOIP_COUNTRY_EDITION
|
125
|
+
results.merge!(current_database.country(ip).to_hash)
|
126
|
+
when GEOIP_CITY_EDITION_REV1
|
127
|
+
results.merge!(current_database.city(ip).to_hash)
|
128
|
+
results.merge!(:netmask=>current_database.netmask(ip))
|
129
|
+
iprange = current_database.range_by_ip(ip)
|
130
|
+
results.merge!(:first_ip => iprange[0],:last_ip => iprange[1])
|
131
|
+
when GEOIP_ISP_EDITION
|
132
|
+
results.merge!(:isp=>current_database.isp(ip))
|
133
|
+
when GEOIP_ORG_EDITION
|
134
|
+
results.merge!(current_database.filename[/([^\/]+)$/][/(?:GeoIP)?([^.]+)/,1].downcase.to_sym => current_database.isp(ip))
|
135
|
+
when GEOIP_ASNUM_EDITION
|
136
|
+
results.merge!(current_database.asn(ip).to_hash)
|
137
|
+
else
|
138
|
+
puts "Unknown or Unsupported GeoIP database type:"
|
139
|
+
puts "filename:#{current_database.filename} => database_type:#{current_database.database_type}"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
results
|
143
|
+
end
|
144
|
+
end
|
metadata
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: geoip_multi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ryan Harris
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-12-03 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: geoip
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.3.3
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.3.3
|
30
|
+
description: ==Extends native ruby geoip gem. Adds support for netmask() and range_by_ip()
|
31
|
+
methods to the GeoIP class and creates a new class GeoIPMulti that performs lookups
|
32
|
+
on multiple GeoIP databases with a single lookup() method
|
33
|
+
email: rubygems.rharris@neverbox.com
|
34
|
+
executables: []
|
35
|
+
extensions: []
|
36
|
+
extra_rdoc_files: []
|
37
|
+
files:
|
38
|
+
- lib/geoip_multi.rb
|
39
|
+
homepage: http://github.com/rlh6f/GeoIPMulti
|
40
|
+
licenses:
|
41
|
+
- GPL
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options: []
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ! '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ! '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
requirements: []
|
59
|
+
rubyforge_project:
|
60
|
+
rubygems_version: 1.8.23
|
61
|
+
signing_key:
|
62
|
+
specification_version: 3
|
63
|
+
summary: Extension of geoip
|
64
|
+
test_files: []
|