ip 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/examples/check-included.rb +27 -0
- data/examples/check-overlap.rb +26 -0
- data/examples/generate-a-records.rb +26 -0
- data/lib/ip.rb +9 -339
- data/lib/ip/address.rb +393 -0
- data/lib/ip/cidr.rb +192 -0
- data/lib/ip/range.rb +54 -0
- data/lib/ip/util.rb +144 -0
- data/test/ip.rb +394 -84
- metadata +10 -2
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Checks if a given IP address exists in a subnet.
|
4
|
+
#
|
5
|
+
# Takes either IPv6 or IPv4.
|
6
|
+
#
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'rubygems'
|
10
|
+
rescue LoadError => e
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'ip'
|
14
|
+
|
15
|
+
if !ARGV[0] or !ARGV[1]
|
16
|
+
$stderr.puts "usage: #{File.basename($0)} <cidr> <ip>"
|
17
|
+
exit -1
|
18
|
+
end
|
19
|
+
|
20
|
+
if IP::CIDR.new(ARGV[0]).includes? IP::Address::Util.string_to_ip(ARGV[1])
|
21
|
+
$stderr.puts "IP #{ARGV[1]} exists in the #{ARGV[0]} subnet"
|
22
|
+
exit 0
|
23
|
+
else
|
24
|
+
$stderr.puts "IP #{ARGV[1]} does not exist in the #{ARGV[0]} subnet"
|
25
|
+
exit 1
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# given two CIDR formatted addresses, check for overlaps.
|
4
|
+
#
|
5
|
+
# Takes either IPv6 or IPv4.
|
6
|
+
#
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'rubygems'
|
10
|
+
rescue LoadError => e
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'ip'
|
14
|
+
|
15
|
+
if !ARGV[0] or !ARGV[1]
|
16
|
+
$stderr.puts "usage: #{File.basename($0)} <cidr> <cidr>"
|
17
|
+
exit -1
|
18
|
+
end
|
19
|
+
|
20
|
+
if IP::CIDR.new(ARGV[0]).overlaps? IP::CIDR.new(ARGV[1])
|
21
|
+
$stderr.puts "These address ranges overlap."
|
22
|
+
exit 1
|
23
|
+
else
|
24
|
+
$stderr.puts "No overlaps"
|
25
|
+
exit 0
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Generate a set of A records suitable for inclusion in a
|
4
|
+
# zone.
|
5
|
+
#
|
6
|
+
# Takes two IP addresses as a range to generate.
|
7
|
+
#
|
8
|
+
|
9
|
+
begin
|
10
|
+
require 'rubygems'
|
11
|
+
rescue LoadError => e
|
12
|
+
end
|
13
|
+
|
14
|
+
require 'ip'
|
15
|
+
|
16
|
+
if !ARGV[0] or !ARGV[1]
|
17
|
+
$stderr.puts "usage: #{File.basename($0)} <start ip> <end ip>"
|
18
|
+
exit -1
|
19
|
+
end
|
20
|
+
|
21
|
+
$fmt = "%15.15s IN A %15.15s"
|
22
|
+
|
23
|
+
IP::Range[ARGV[0], ARGV[1]].each do |ip|
|
24
|
+
hostname = ip.ip_address.gsub(/\./, "-")
|
25
|
+
puts ($fmt % [hostname, ip.ip_address])
|
26
|
+
end
|
data/lib/ip.rb
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
# Author:: Erik Hollensbe
|
6
6
|
# License:: BSD
|
7
7
|
# Contact:: erik@hollensbe.org
|
8
|
+
# Copyright:: Copyright (c) 2005-2006 Erik Hollensbe
|
8
9
|
#
|
9
10
|
# IP is, as mentioned above, a collection of tools to work
|
10
11
|
# with IP addresses. There are three major classes included
|
@@ -30,7 +31,7 @@
|
|
30
31
|
# methods that made code easier to understand and/or clearer, and
|
31
32
|
# making plenty of suggestions made creating this module much easier.
|
32
33
|
#
|
33
|
-
|
34
|
+
#--
|
34
35
|
#
|
35
36
|
# The compilation of software known as ip.rb is distributed under the
|
36
37
|
# following terms:
|
@@ -54,6 +55,7 @@
|
|
54
55
|
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
55
56
|
# SUCH DAMAGE.
|
56
57
|
#
|
58
|
+
#++
|
57
59
|
|
58
60
|
class IP
|
59
61
|
|
@@ -74,344 +76,12 @@ class IP
|
|
74
76
|
class BoundaryException < Exception
|
75
77
|
end
|
76
78
|
|
77
|
-
#
|
78
|
-
# IP::Range - Calculates a range of IP addresses, and returns an
|
79
|
-
# Array of IP::Address objects.
|
80
|
-
#
|
81
|
-
# Usage::
|
82
|
-
#
|
83
|
-
# IP::Range['10.0.0.1', '10.0.0.2'] => IP::Address objects between
|
84
|
-
# 10.0.0.1 and 10.0.0.2 (inclusive)
|
85
|
-
#
|
86
|
-
# IP::Range can also take two IP::Address objects.
|
87
|
-
#
|
88
|
-
# Will throw a IP::AddressException if for some reason addresses
|
89
|
-
# cannot be parsed.
|
90
|
-
#
|
91
|
-
|
92
|
-
class Range
|
93
|
-
|
94
|
-
#
|
95
|
-
# See the documentation for IP::Range for more information on this
|
96
|
-
# method.
|
97
|
-
#
|
98
|
-
|
99
|
-
def Range.[](addr1, addr2)
|
100
|
-
raw1, raw2 = [nil, nil]
|
101
|
-
|
102
|
-
if addr1.kind_of? String
|
103
|
-
raw1 = IP::Address::Util.pack(IP::Address.new(addr1))
|
104
|
-
elsif addr1.kind_of? IP::Address
|
105
|
-
raw1 = IP::Address::Util.pack(addr1)
|
106
|
-
else
|
107
|
-
raise IP::AddressException("IP Address is not type String or IP::Address")
|
108
|
-
end
|
109
|
-
|
110
|
-
if addr2.kind_of? String
|
111
|
-
raw2 = IP::Address::Util.pack(IP::Address.new(addr2))
|
112
|
-
elsif addr2.kind_of? IP::Address
|
113
|
-
raw2 = IP::Address::Util.pack(addr2)
|
114
|
-
else
|
115
|
-
raise IP::AddressException("IP Address is not type String or IP::Address")
|
116
|
-
end
|
117
|
-
|
118
|
-
range = []
|
119
|
-
|
120
|
-
(raw1..raw2).each { |x| range.push(IP::Address::Util.unpack(x)) }
|
121
|
-
|
122
|
-
return range
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
#
|
127
|
-
# IP::CIDR - Works with Classless Inter-Domain Routing formats, such
|
128
|
-
# as 10.0.0.1/32 or 10.0.0.1/255.255.255.255
|
129
|
-
#
|
130
|
-
|
131
|
-
class CIDR
|
132
|
-
#
|
133
|
-
# Contains the original CIDR you fed it, returned as a string.
|
134
|
-
#
|
135
|
-
attr_reader :cidr
|
136
|
-
#
|
137
|
-
# Contains the IP address (LHS) only. Returned as an IP::Address
|
138
|
-
# object.
|
139
|
-
#
|
140
|
-
attr_reader :ip
|
141
|
-
#
|
142
|
-
# Contains the integer-based (short) netmask (RHS) only. Returned as an
|
143
|
-
# integer.
|
144
|
-
#
|
145
|
-
attr_reader :mask
|
146
|
-
|
147
|
-
#
|
148
|
-
# Given a string of format X.X.X.X/X, in standard CIDR notation,
|
149
|
-
# this will construct a IP::CIDR object.
|
150
|
-
#
|
151
|
-
def initialize(cidr)
|
152
|
-
if !cidr.kind_of? String
|
153
|
-
raise IP::AddressException.new("CIDR value is not of type String")
|
154
|
-
end
|
155
|
-
|
156
|
-
@cidr = cidr
|
157
|
-
@ip, @mask = cidr.split(/\//, 2)
|
158
|
-
|
159
|
-
if @ip.nil? or @mask.nil?
|
160
|
-
raise IP::AddressException.new("CIDR is not valid - invalid format")
|
161
|
-
end
|
162
|
-
|
163
|
-
if @mask.length == 0 or /[^0-9.]/.match @mask
|
164
|
-
raise IP::AddressException.new("CIDR RHS is not valid - #{@mask}")
|
165
|
-
end
|
166
|
-
|
167
|
-
if @mask.length > 2
|
168
|
-
# this will throw an exception if the netmask is malformed.
|
169
|
-
@mask = IP::Address::Util.short_netmask(IP::Address.new(@mask))
|
170
|
-
end
|
171
|
-
|
172
|
-
@ip = IP::Address.new(@ip)
|
173
|
-
@mask = @mask.to_i
|
174
|
-
end
|
175
|
-
|
176
|
-
def netmask
|
177
|
-
warn "IP::CIDR#netmask is deprecated. Please use IP::CIDR#long_netmask instead."
|
178
|
-
return self.long_netmask
|
179
|
-
end
|
180
|
-
|
181
|
-
#
|
182
|
-
# This produces the long netmask (eg. 255.255.255.255) of the CIDR in an
|
183
|
-
# IP::Address object.
|
184
|
-
#
|
185
|
-
def long_netmask
|
186
|
-
return IP::Address::Util.long_netmask(@mask)
|
187
|
-
end
|
188
|
-
|
189
|
-
#
|
190
|
-
# This produces the short netmask (eg. 32) of the CIDR in an IP::Address
|
191
|
-
# object.
|
192
|
-
#
|
193
|
-
|
194
|
-
def short_netmask
|
195
|
-
return @mask
|
196
|
-
end
|
197
|
-
|
198
|
-
#
|
199
|
-
# This produces a range ala IP::Range, but only for the subnet
|
200
|
-
# defined by the CIDR object.
|
201
|
-
#
|
202
|
-
def range
|
203
|
-
return IP::Range[self.first_ip, self.last_ip]
|
204
|
-
end
|
205
|
-
|
206
|
-
#
|
207
|
-
# This returns the first ip address of the cidr as an IP::Address object.
|
208
|
-
#
|
209
|
-
def first_ip
|
210
|
-
rawip = IP::Address::Util.pack(@ip)
|
211
|
-
rawnm = 0xFFFFFFFF << (32 - @mask)
|
212
|
-
lower = rawip & rawnm
|
213
|
-
return IP::Address::Util.unpack(lower)
|
214
|
-
end
|
215
|
-
|
216
|
-
#
|
217
|
-
# This returns the last ip address of the cidr as an IP::Address object.
|
218
|
-
#
|
219
|
-
def last_ip
|
220
|
-
rawip = IP::Address::Util.pack(@ip)
|
221
|
-
rawnm = 0xFFFFFFFF << (32 - @mask)
|
222
|
-
upper = rawip | ~rawnm
|
223
|
-
return IP::Address::Util.unpack(upper)
|
224
|
-
end
|
225
|
-
|
226
|
-
#
|
227
|
-
# This will take another IP::CIDR object as an argument and check to see
|
228
|
-
# if it overlaps with this cidr object. Returns true/false on overlap.
|
229
|
-
#
|
230
|
-
# This also throws a TypeError if passed invalid data.
|
231
|
-
#
|
232
|
-
def overlaps?(other_cidr)
|
233
|
-
raise TypeError.new("Expected object of type IP::CIDR") unless(other_cidr.kind_of?(IP::CIDR))
|
234
|
-
|
235
|
-
myfirst = IP::Address::Util.pack(self.first_ip)
|
236
|
-
mylast = IP::Address::Util.pack(self.last_ip)
|
237
|
-
|
238
|
-
otherfirst = IP::Address::Util.pack(other_cidr.first_ip)
|
239
|
-
otherlast = IP::Address::Util.pack(other_cidr.last_ip)
|
240
|
-
|
241
|
-
return ((myfirst >= otherfirst && myfirst <= otherlast) ||
|
242
|
-
(mylast <= otherlast && mylast >= otherfirst) ||
|
243
|
-
(otherfirst >= myfirst && otherfirst <= mylast)) ? true : false;
|
244
|
-
end
|
245
|
-
|
246
|
-
end
|
247
|
-
|
248
|
-
#
|
249
|
-
# IP::Address - utility class to work with dotted-quad IP addresses.
|
250
|
-
#
|
251
|
-
class Address
|
252
|
-
#
|
253
|
-
# This original IP Address you passed it, returned as a string.
|
254
|
-
#
|
255
|
-
attr_reader :ip_address
|
256
|
-
#
|
257
|
-
# This returns an Array of Integer which contains the octets of
|
258
|
-
# the IP, in descending order.
|
259
|
-
#
|
260
|
-
attr_reader :octets
|
261
|
-
|
262
|
-
#
|
263
|
-
# When given a string, constructs an IP::Address object.
|
264
|
-
#
|
265
|
-
def initialize(ip_address)
|
266
|
-
if ! ip_address.kind_of? String
|
267
|
-
raise IP::AddressException.new("Fed IP address is not String")
|
268
|
-
end
|
269
|
-
@ip_address = ip_address
|
270
|
-
|
271
|
-
#
|
272
|
-
# Unbeknowest by me, to_i will not throw an exception if the string
|
273
|
-
# can't be converted cleanly - it just truncates, similar to atoi() and perl's int().
|
274
|
-
#
|
275
|
-
# Code below does a final sanity check.
|
276
|
-
#
|
277
|
-
|
278
|
-
octets = ip_address.split(/\./)
|
279
|
-
octets_i = octets.collect { |x| x.to_i }
|
280
|
-
|
281
|
-
0.upto(octets.length - 1) do |octet|
|
282
|
-
if octets[octet] != octets_i[octet].to_s
|
283
|
-
raise IP::AddressException.new("Integer conversion failed")
|
284
|
-
end
|
285
|
-
end
|
286
|
-
|
287
|
-
@octets = octets_i
|
288
|
-
|
289
|
-
# I made a design decision to allow 0.0.0.0 here.
|
290
|
-
if @octets.length != 4 or @octets.find_all { |x| x > 255 }.length > 0
|
291
|
-
raise IP::AddressException.new("IP address is improperly formed")
|
292
|
-
end
|
293
|
-
end
|
294
|
-
|
295
|
-
#
|
296
|
-
# Returns an octet given the proper index. The octets returned are
|
297
|
-
# Integer types.
|
298
|
-
#
|
299
|
-
def [](num)
|
300
|
-
if num > 3
|
301
|
-
raise IP::BoundaryException.new("Max octet number is 3")
|
302
|
-
end
|
303
|
-
return @octets[num]
|
304
|
-
end
|
305
|
-
|
306
|
-
#
|
307
|
-
# See [].
|
308
|
-
#
|
309
|
-
alias_method :octet, :[]
|
310
|
-
|
311
|
-
#
|
312
|
-
# Class method to pack an IP::Address object into a long integer
|
313
|
-
# used for calculation. Returns a 'FixNum' type.
|
314
|
-
#
|
315
|
-
# This method is deprecated. Please use IP::Address::Util#pack instead.
|
316
|
-
#
|
317
|
-
def Address.pack(ip)
|
318
|
-
warn "IP::Address#pack is deprecated. Please use IP::Address::Util#pack instead."
|
319
|
-
return IP::Address::Util.pack(ip)
|
320
|
-
end
|
321
|
-
|
322
|
-
#
|
323
|
-
# Class method to take a 'FixNum' type and return an IP::Address
|
324
|
-
# object.
|
325
|
-
#
|
326
|
-
# This method is deprecated. Please use IP::Address::Util#unpack instead.
|
327
|
-
#
|
328
|
-
def Address.unpack(ip)
|
329
|
-
warn "IP::Address#unpack is deprecated. Please use IP::Address::Util#unpack instead."
|
330
|
-
return IP::Address::Util.unpack(ip)
|
331
|
-
end
|
332
|
-
|
333
|
-
end
|
334
|
-
|
335
79
|
end
|
336
80
|
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
ret = 0
|
344
|
-
myip = ip.octets.reverse
|
345
|
-
4.times { |x| ret = ret | (myip[x] & 0xFF) << 8*x }
|
346
|
-
return ret
|
347
|
-
end
|
348
|
-
|
349
|
-
module_function :pack
|
350
|
-
|
351
|
-
#
|
352
|
-
# Take a 'FixNum' type and return an IP::Address object.
|
353
|
-
#
|
354
|
-
def unpack(ip)
|
355
|
-
ret = []
|
356
|
-
4.times { |x| ret.push((ip >> 8*x) & 0xFF) }
|
357
|
-
return IP::Address.new(ret.reverse.join("."))
|
358
|
-
end
|
359
|
-
|
360
|
-
module_function :unpack
|
361
|
-
|
362
|
-
#
|
363
|
-
# Given an IP::Address object suitable for a netmask, returns the CIDR-notation
|
364
|
-
# "short" netmask.
|
365
|
-
#
|
366
|
-
# ex:
|
367
|
-
# short_netmask(IP::Address.new("255.255.255.255")) => 32
|
368
|
-
# short_netmask(IP::Address.new("255.255.255.240")) => 28
|
369
|
-
#
|
370
|
-
|
371
|
-
def short_netmask(ip)
|
372
|
-
a = []
|
373
|
-
(0..3).each do |x|
|
374
|
-
if x < 3 && ip[x] < 255 && ip[x+1] > 0
|
375
|
-
raise IP::BoundaryException.new("Invalid Netmask")
|
376
|
-
end
|
377
|
-
a += binary_vector(ip[x])
|
378
|
-
end
|
379
|
-
retval = 0
|
380
|
-
a.each { |x| retval += x }
|
381
|
-
return retval
|
382
|
-
end
|
383
|
-
|
384
|
-
module_function :short_netmask
|
385
|
-
|
386
|
-
#
|
387
|
-
# Given a CIDR-notation "short" netmask, returns a IP::Address object containing
|
388
|
-
# the equivalent "long" netmask.
|
389
|
-
#
|
390
|
-
# ex:
|
391
|
-
# long_netmask(32) => IP::Address object of "255.255.255.255"
|
392
|
-
# long_netmask(28) => IP::Address object of "255.255.255.240"
|
393
|
-
#
|
394
|
-
|
395
|
-
def long_netmask(short)
|
396
|
-
raw = 0xFFFFFFFF << (32 - short)
|
397
|
-
return IP::Address::Util.unpack(raw)
|
398
|
-
end
|
399
|
-
|
400
|
-
module_function :long_netmask
|
401
|
-
|
402
|
-
#
|
403
|
-
# Given a number (presumably an octet), will produce a binary vector indicating the
|
404
|
-
# on/off positions as 1 or 0.
|
405
|
-
#
|
406
|
-
# ex:
|
407
|
-
# binary_vector(255) => [1, 1, 1, 1, 1, 1, 1, 1]
|
408
|
-
# binary_vector(240) => [1, 1, 1, 1, 0, 0, 0, 0]
|
409
|
-
#
|
81
|
+
$:.unshift(File.dirname(__FILE__))
|
82
|
+
require 'ip/address'
|
83
|
+
require 'ip/cidr'
|
84
|
+
require 'ip/range'
|
85
|
+
require 'ip/util'
|
86
|
+
$:.shift
|
410
87
|
|
411
|
-
def binary_vector(octet)
|
412
|
-
return octet.to_i.to_s(2).split(//).collect { |x| x.to_i }
|
413
|
-
end
|
414
|
-
|
415
|
-
module_function :binary_vector
|
416
|
-
|
417
|
-
end
|