geoip_multi 0.1.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.
Files changed (2) hide show
  1. data/lib/geoip_multi.rb +144 -0
  2. metadata +64 -0
@@ -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: []