ipadmin 0.3.0 → 0.4.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/README +190 -151
- data/lib/cidr.rb +412 -210
- data/lib/eui.rb +92 -115
- data/lib/methods.rb +409 -438
- data/lib/tree.rb +609 -367
- data/tests/cidr_test.rb +56 -43
- data/tests/eui_test.rb +16 -14
- data/tests/methods_test.rb +191 -185
- data/tests/tree_test.rb +191 -231
- metadata +3 -3
data/lib/tree.rb
CHANGED
@@ -1,9 +1,3 @@
|
|
1
|
-
=begin rdoc
|
2
|
-
Copyright (c) 2006 Dustin Spinhirne -
|
3
|
-
Licensed under the same terms as Ruby, No Warranty is provided.
|
4
|
-
=end
|
5
|
-
|
6
|
-
|
7
1
|
module IPAdmin
|
8
2
|
class Tree
|
9
3
|
|
@@ -14,11 +8,19 @@ class Tree
|
|
14
8
|
# @version
|
15
9
|
|
16
10
|
#==============================================================================#
|
17
|
-
#
|
11
|
+
# initialize()
|
18
12
|
#==============================================================================#
|
19
13
|
|
20
|
-
|
21
|
-
|
14
|
+
# - Arguments:
|
15
|
+
# * none
|
16
|
+
#
|
17
|
+
# Examples:
|
18
|
+
# tree = IPAdmin::Tree.new()
|
19
|
+
#
|
20
|
+
def initialize(options=nil)
|
21
|
+
# root of our ordered IP tree
|
22
|
+
@root = NetStruct.new(nil, nil, [])
|
23
|
+
end
|
22
24
|
|
23
25
|
#======================================#
|
24
26
|
#
|
@@ -26,42 +28,68 @@ class Tree
|
|
26
28
|
|
27
29
|
|
28
30
|
#==============================================================================#
|
29
|
-
#
|
31
|
+
# add!()
|
30
32
|
#==============================================================================#
|
31
33
|
|
34
|
+
# Add a CIDR address or IPAdmin::CIDR object to the tree.
|
35
|
+
#
|
32
36
|
# - Arguments:
|
33
|
-
# *
|
34
|
-
# - :Version -- IP version - Integer
|
37
|
+
# * CIDR address or IPAdmin::CIDR object
|
35
38
|
#
|
36
|
-
#
|
37
|
-
#
|
39
|
+
# - Returns:
|
40
|
+
# * nothing
|
38
41
|
#
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
if ( options.has_key?(:Version) )
|
45
|
-
@version = options[:Version]
|
42
|
+
# Examples:
|
43
|
+
# tree.add!('192.168.1.0/24')
|
44
|
+
#
|
45
|
+
def add!(new)
|
46
|
+
duplicate = false
|
46
47
|
|
47
|
-
|
48
|
-
|
48
|
+
# validate object
|
49
|
+
if ( !new.kind_of?(IPAdmin::CIDR) )
|
50
|
+
begin
|
51
|
+
cidr = IPAdmin::CIDR.new(:CIDR => new)
|
52
|
+
rescue Exception => error
|
53
|
+
raise ArgumentError, "Provided argument raised the following " +
|
54
|
+
"errors: #{error}"
|
49
55
|
end
|
50
56
|
else
|
51
|
-
|
57
|
+
cidr = IPAdmin::CIDR.new(:PackedIP => new.packed_ip,
|
58
|
+
:PackedNetmask => new.packed_netmask,
|
59
|
+
:Version => new.version,
|
60
|
+
:Tag => new.tag)
|
61
|
+
end
|
62
|
+
|
63
|
+
version = cidr.version
|
64
|
+
new_entry = NetStruct.new(cidr, nil, [])
|
65
|
+
|
66
|
+
# find cidr's parent
|
67
|
+
new_entry.parent = find_parent(cidr, @root)
|
68
|
+
|
69
|
+
# check parent for subnets of cidr
|
70
|
+
new_entry.parent.children.each do |old_entry|
|
71
|
+
if (old_entry.cidr.version == version)
|
72
|
+
comp = IPAdmin.compare(cidr,old_entry.cidr)
|
73
|
+
if (comp && comp[0] == cidr)
|
74
|
+
old_entry.parent = new_entry
|
75
|
+
new_entry.children.push(old_entry)
|
76
|
+
elsif (comp && comp == 1)
|
77
|
+
duplicate = true
|
78
|
+
break
|
79
|
+
end
|
80
|
+
end
|
52
81
|
end
|
53
82
|
|
54
|
-
if (
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
@max_bits = 128
|
59
|
-
@all_f = 2**@max_bits - 1
|
60
|
-
end
|
83
|
+
if (!duplicate)
|
84
|
+
new_entry.children.each do |old_entry|
|
85
|
+
new_entry.parent.children.delete(old_entry)
|
86
|
+
end
|
61
87
|
|
62
|
-
|
63
|
-
|
88
|
+
# add new object as an ordered entry to parent.children
|
89
|
+
add_to_parent(new_entry,new_entry.parent)
|
90
|
+
end
|
64
91
|
|
92
|
+
return()
|
65
93
|
end
|
66
94
|
|
67
95
|
#======================================#
|
@@ -70,68 +98,118 @@ class Tree
|
|
70
98
|
|
71
99
|
|
72
100
|
#==============================================================================#
|
73
|
-
#
|
101
|
+
# ancestors()
|
74
102
|
#==============================================================================#
|
75
103
|
|
76
|
-
#
|
104
|
+
# Returns all the ancestors of the provided CIDR addresses.
|
77
105
|
#
|
78
106
|
# - Arguments:
|
79
|
-
# * CIDR object
|
107
|
+
# * CIDR address or IPAdmin::CIDR object
|
80
108
|
#
|
81
109
|
# - Returns:
|
82
|
-
# *
|
110
|
+
# * Array of IPAdmin::CIDR objects
|
83
111
|
#
|
84
|
-
#
|
85
|
-
# tree.
|
112
|
+
# Examples:
|
113
|
+
# puts tree.ancestors('192.168.1.0/27')
|
86
114
|
#
|
87
|
-
def
|
88
|
-
|
115
|
+
def ancestors(cidr)
|
89
116
|
# validate object
|
90
|
-
if ( !
|
91
|
-
|
92
|
-
|
117
|
+
if ( !cidr.kind_of?(IPAdmin::CIDR) )
|
118
|
+
begin
|
119
|
+
cidr = IPAdmin::CIDR.new(:CIDR => cidr)
|
120
|
+
rescue Exception => error
|
121
|
+
raise ArgumentError, "Provided argument raised the following " +
|
122
|
+
"errors: #{error}"
|
123
|
+
end
|
93
124
|
end
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
125
|
+
|
126
|
+
list = []
|
127
|
+
parent = find_parent(cidr,@root)
|
128
|
+
|
129
|
+
until (parent == @root)
|
130
|
+
list.push(parent.cidr)
|
131
|
+
parent = parent.parent
|
98
132
|
end
|
99
133
|
|
100
|
-
|
134
|
+
return(list)
|
135
|
+
end
|
101
136
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
home_branch = home_struct.subnets if (search_results)
|
106
|
-
home_branch = @root if (!home_branch)
|
137
|
+
#======================================#
|
138
|
+
#
|
139
|
+
#======================================#
|
107
140
|
|
108
|
-
# make sure we dont have a duplicate
|
109
|
-
if (home_struct)
|
110
|
-
if ( (net_struct.network == home_struct.network) &&
|
111
|
-
(net_struct.netmask == home_struct.netmask) )
|
112
|
-
raise "Attempted to add #{object.desc()} multiple times."
|
113
|
-
end
|
114
|
-
end
|
115
141
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
home_branch.each do |entry|
|
120
|
-
is_contained = contains(net_struct, entry)
|
142
|
+
#==============================================================================#
|
143
|
+
# children()
|
144
|
+
#==============================================================================#
|
121
145
|
|
122
|
-
|
123
|
-
|
146
|
+
# Returns all the immediate children of the provided CIDR addresses.
|
147
|
+
#
|
148
|
+
# - Arguments:
|
149
|
+
# * CIDR address or IPAdmin::CIDR object
|
150
|
+
#
|
151
|
+
# - Returns:
|
152
|
+
# * Array of IPAdmin::CIDR objects
|
153
|
+
#
|
154
|
+
# Examples:
|
155
|
+
# puts tree.children('192.168.1.0/24')
|
156
|
+
#
|
157
|
+
def children(cidr)
|
158
|
+
# validate object
|
159
|
+
if ( !cidr.kind_of?(IPAdmin::CIDR) )
|
160
|
+
begin
|
161
|
+
cidr = IPAdmin::CIDR.new(:CIDR => cidr)
|
162
|
+
rescue Exception => error
|
163
|
+
raise ArgumentError, "Provided argument raised the following " +
|
164
|
+
"errors: #{error}"
|
124
165
|
end
|
125
166
|
end
|
126
167
|
|
127
|
-
|
128
|
-
|
168
|
+
list = []
|
169
|
+
find_me(cidr).children.each do |child|
|
170
|
+
list.push(child.cidr)
|
171
|
+
end
|
172
|
+
|
173
|
+
return(list)
|
174
|
+
end
|
175
|
+
|
176
|
+
#======================================#
|
177
|
+
#
|
178
|
+
#======================================#
|
179
|
+
|
180
|
+
|
181
|
+
#==============================================================================#
|
182
|
+
# descendants
|
183
|
+
#==============================================================================#
|
184
|
+
|
185
|
+
# Return all descendants of the provided CIDR address.
|
186
|
+
#
|
187
|
+
# - Arguments:
|
188
|
+
# * CIDR address or IPAdmin::CIDR object
|
189
|
+
#
|
190
|
+
# - Returns:
|
191
|
+
# * Array of IPAdmin::CIDR objects
|
192
|
+
#
|
193
|
+
# Examples:
|
194
|
+
# descendants = tree.descendants('192.168.1.0/24')
|
195
|
+
#
|
196
|
+
def descendants(cidr)
|
197
|
+
list = []
|
198
|
+
|
199
|
+
# validate object
|
200
|
+
if ( !cidr.kind_of?(IPAdmin::CIDR) )
|
201
|
+
begin
|
202
|
+
cidr = IPAdmin::CIDR.new(:CIDR => cidr)
|
203
|
+
rescue Exception => error
|
204
|
+
raise ArgumentError, "Provided argument raised the following " +
|
205
|
+
"errors: #{error}"
|
206
|
+
end
|
129
207
|
end
|
130
208
|
|
131
|
-
|
132
|
-
|
209
|
+
me = find_me(cidr)
|
210
|
+
dump_children(me).each {|x| list.push(x[:NetStruct].cidr)} if (me)
|
133
211
|
|
134
|
-
return(
|
212
|
+
return(list)
|
135
213
|
end
|
136
214
|
|
137
215
|
#======================================#
|
@@ -140,39 +218,46 @@ class Tree
|
|
140
218
|
|
141
219
|
|
142
220
|
#==============================================================================#
|
143
|
-
#
|
221
|
+
# delete!()
|
144
222
|
#==============================================================================#
|
145
223
|
|
146
|
-
#
|
147
|
-
# and return a new tree. The supernetting of subnets will only occur in
|
148
|
-
# situations where the newly created supernet will not result in the
|
149
|
-
# 'creation' of additional space. For example the following blocks
|
150
|
-
# (192.168.0.0/24, 192.168.1.0/24, and 192.168.2.0/24) would merge into
|
151
|
-
# 192.168.0.0/23 and 192.168.2.0/24 rather than into 192.168.0.0/22.
|
224
|
+
# Remove the provided CIDR address from the tree.
|
152
225
|
#
|
153
226
|
# - Arguments:
|
154
|
-
# *
|
227
|
+
# * CIDR address of IPAdmin::CIDR object
|
155
228
|
#
|
156
229
|
# - Returns:
|
157
|
-
# *
|
158
|
-
#
|
159
|
-
#
|
160
|
-
#
|
161
|
-
#
|
162
|
-
def
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
cidr = IPAdmin::CIDR.new(:CIDR => "#{network}/#{netmask}")
|
173
|
-
tree.add(cidr)
|
230
|
+
# * true on success or false on fail
|
231
|
+
#
|
232
|
+
# Examples:
|
233
|
+
# did_remove = tree.remove!('192.168.1.0/24')
|
234
|
+
#
|
235
|
+
def delete!(cidr)
|
236
|
+
removed = false
|
237
|
+
|
238
|
+
# validate object
|
239
|
+
if ( !cidr.kind_of?(IPAdmin::CIDR) )
|
240
|
+
begin
|
241
|
+
cidr = IPAdmin::CIDR.new(:CIDR => cidr)
|
242
|
+
rescue Exception => error
|
243
|
+
raise ArgumentError, "Provided argument raised the following " +
|
244
|
+
"errors: #{error}"
|
174
245
|
end
|
175
|
-
|
246
|
+
end
|
247
|
+
|
248
|
+
# find matching
|
249
|
+
me = find_me(cidr)
|
250
|
+
|
251
|
+
# remove
|
252
|
+
if (me)
|
253
|
+
parent = me.parent
|
254
|
+
children = me.children
|
255
|
+
parent.children.delete(me)
|
256
|
+
children.each {|x| add_to_parent(x,parent)}
|
257
|
+
removed = true
|
258
|
+
end
|
259
|
+
|
260
|
+
return(removed)
|
176
261
|
end
|
177
262
|
|
178
263
|
#======================================#
|
@@ -191,20 +276,19 @@ class Tree
|
|
191
276
|
#
|
192
277
|
# - Returns:
|
193
278
|
# * ordered array of hashes with the following fields:
|
194
|
-
# - :
|
279
|
+
# - :CIDR => IPAdmin::CIDR object
|
195
280
|
# - :Depth => (depth level in tree)
|
196
|
-
#
|
281
|
+
# Examples:
|
197
282
|
# dumped = tree.dump()
|
198
283
|
#
|
199
284
|
def dump()
|
200
285
|
list = []
|
201
|
-
dumped =
|
286
|
+
dumped = dump_children(@root)
|
202
287
|
|
203
288
|
dumped.each do |entry|
|
204
289
|
depth = entry[:Depth]
|
205
290
|
net_struct = entry[:NetStruct]
|
206
|
-
|
207
|
-
list.push({:Depth => depth, :Object => object})
|
291
|
+
list.push({:Depth => depth, :CIDR => net_struct.cidr})
|
208
292
|
end
|
209
293
|
|
210
294
|
return(list)
|
@@ -219,43 +303,31 @@ class Tree
|
|
219
303
|
# exists?()
|
220
304
|
#==============================================================================#
|
221
305
|
|
222
|
-
# Has
|
306
|
+
# Has a CIDR address already been added to the tree?
|
223
307
|
#
|
224
308
|
# - Arguments:
|
225
|
-
# * CIDR object
|
309
|
+
# * CIDR address or IPAdmin::CIDR object
|
226
310
|
#
|
227
311
|
# - Returns:
|
228
312
|
# * true or false
|
229
313
|
#
|
230
|
-
#
|
231
|
-
# added = tree.exists?(
|
314
|
+
# Examples:
|
315
|
+
# added = tree.exists?('192.168.1.0/24')
|
232
316
|
#
|
233
|
-
def exists?(
|
317
|
+
def exists?(cidr)
|
318
|
+
found = false
|
234
319
|
|
235
320
|
# validate object
|
236
|
-
if ( !
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
raise "IP version #{object.version} is incompatible with " +
|
243
|
-
"Tree IP version #{@version}."
|
244
|
-
end
|
245
|
-
|
246
|
-
net_struct = IPAdmin.create_net_struct(object)
|
247
|
-
home_struct,home_branch = find_home(net_struct, @root)
|
248
|
-
|
249
|
-
# check for match
|
250
|
-
found = false
|
251
|
-
if (home_struct)
|
252
|
-
if ( (net_struct.network == home_struct.network) &&
|
253
|
-
(net_struct.netmask == home_struct.netmask) )
|
254
|
-
found = true
|
321
|
+
if ( !cidr.kind_of?(IPAdmin::CIDR) )
|
322
|
+
begin
|
323
|
+
cidr = IPAdmin::CIDR.new(:CIDR => cidr)
|
324
|
+
rescue Exception => error
|
325
|
+
raise ArgumentError, "Provided argument raised the following " +
|
326
|
+
"errors: #{error}"
|
255
327
|
end
|
256
328
|
end
|
257
329
|
|
258
|
-
|
330
|
+
found = true if (find_me(cidr))
|
259
331
|
return(found)
|
260
332
|
end
|
261
333
|
|
@@ -265,37 +337,76 @@ class Tree
|
|
265
337
|
|
266
338
|
|
267
339
|
#==============================================================================#
|
268
|
-
#
|
340
|
+
# fill_in!()
|
269
341
|
#==============================================================================#
|
270
342
|
|
271
|
-
#
|
272
|
-
# IPAdmin::CIDR object belongs. Useful for performing 'routing table' lookups.
|
343
|
+
# Fill in the missing subnets of a particular CIDR.
|
273
344
|
#
|
274
345
|
# - Arguments:
|
275
|
-
# * CIDR object
|
346
|
+
# * CIDR address or IPAdmin::CIDR object
|
276
347
|
#
|
277
348
|
# - Returns:
|
278
|
-
# *
|
349
|
+
# * true or false
|
279
350
|
#
|
280
|
-
#
|
281
|
-
#
|
351
|
+
# Examples:
|
352
|
+
# success = tree.fill_in!('192.168.1.0/24')
|
282
353
|
#
|
283
|
-
def
|
284
|
-
|
285
|
-
|
286
|
-
|
354
|
+
def fill_in!(cidr)
|
355
|
+
filled = false
|
356
|
+
|
357
|
+
# validate object
|
358
|
+
if ( !cidr.kind_of?(IPAdmin::CIDR) )
|
359
|
+
begin
|
360
|
+
cidr = IPAdmin::CIDR.new(:CIDR => cidr)
|
361
|
+
rescue Exception => error
|
362
|
+
raise ArgumentError, "Provided argument raised the following " +
|
363
|
+
"errors: #{error}"
|
364
|
+
end
|
287
365
|
end
|
288
366
|
|
289
|
-
|
290
|
-
|
291
|
-
|
367
|
+
me = find_me(cidr)
|
368
|
+
if (me && me.children.length != 0)
|
369
|
+
list = []
|
370
|
+
me.children.each {|x| list.push(x.cidr)}
|
371
|
+
me.cidr.fill_in(:List => list, :Objectify => true).each do |cidr|
|
372
|
+
self.add!(cidr)
|
373
|
+
end
|
374
|
+
filled = true
|
292
375
|
end
|
376
|
+
return(filled)
|
377
|
+
end
|
293
378
|
|
294
|
-
|
295
|
-
|
296
|
-
|
379
|
+
#======================================#
|
380
|
+
#
|
381
|
+
#======================================#
|
297
382
|
|
298
|
-
|
383
|
+
|
384
|
+
#==============================================================================#
|
385
|
+
# find()
|
386
|
+
#==============================================================================#
|
387
|
+
|
388
|
+
# Find and return a CIDR from within the tree.
|
389
|
+
#
|
390
|
+
# - Arguments:
|
391
|
+
# * CIDR address or IPAdmin::CIDR object
|
392
|
+
#
|
393
|
+
# - Returns:
|
394
|
+
# * IPAdmin::CIDR object, or nil
|
395
|
+
#
|
396
|
+
# Examples:
|
397
|
+
# cidr = tree.find('192.168.1.0/24')
|
398
|
+
#
|
399
|
+
def find(cidr)
|
400
|
+
if ( !cidr.kind_of?(IPAdmin::CIDR) )
|
401
|
+
begin
|
402
|
+
cidr = IPAdmin::CIDR.new(:CIDR => cidr)
|
403
|
+
rescue Exception => error
|
404
|
+
raise ArgumentError, "Provided argument raised the following " +
|
405
|
+
"errors: #{error}"
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
return(find_me(cidr).cidr)
|
299
410
|
end
|
300
411
|
|
301
412
|
#======================================#
|
@@ -307,86 +418,110 @@ class Tree
|
|
307
418
|
# find_space()
|
308
419
|
#==============================================================================#
|
309
420
|
|
310
|
-
# Find
|
311
|
-
#
|
312
|
-
# then method returns all entries that can fit a single IP.
|
421
|
+
# Find subnets that are of at least size X. Only subnets that are not themselves
|
422
|
+
# subnetted will be returned.
|
313
423
|
#
|
314
424
|
# - Arguments:
|
315
|
-
# * Hash with the following fields:
|
316
|
-
# - :
|
317
|
-
# - :
|
318
|
-
# - :
|
425
|
+
# * Minimum subnet size in bits, or a Hash with the following fields:
|
426
|
+
# - :Subnet - minimum subnet size in bits for returned subnets
|
427
|
+
# - :IPCount - minimum IP count per subnet required for returned subnets
|
428
|
+
# - :Version - restrict results to IPvX
|
319
429
|
#
|
320
430
|
# - Returns:
|
321
|
-
# * Array of CIDR objects
|
431
|
+
# * Array of IPAdmin::CIDR objects
|
322
432
|
#
|
323
433
|
# - Notes:
|
324
|
-
#
|
434
|
+
# * :Subnet takes precedence over :IPCount
|
325
435
|
#
|
326
|
-
#
|
327
|
-
#
|
328
|
-
# list = tree.find_space(:IPCount => 33, :Limit => 2)
|
436
|
+
# Examples:
|
437
|
+
# subnets = tree.find_space(:IPCount => 16)
|
329
438
|
#
|
330
439
|
def find_space(options)
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
440
|
+
version = nil
|
441
|
+
if (options.kind_of? Integer)
|
442
|
+
bits4 = options
|
443
|
+
bits6 = options
|
444
|
+
elsif (options.kind_of? Hash)
|
445
|
+
if (options.has_key?(:Version))
|
446
|
+
version = options[:Version]
|
447
|
+
raise "IP version should be 4 or 6, but was #{version}." if (version != 4 && version !=6)
|
448
|
+
end
|
338
449
|
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
450
|
+
if (options.has_key?(:Subnet))
|
451
|
+
bits4 = options[:Subnet]
|
452
|
+
bits6 = options[:Subnet]
|
453
|
+
elsif(options.has_key?(:IPCount))
|
454
|
+
bits4 = IPAdmin.minimum_size(:IPCount => options[:IPCount], :Version => 4)
|
455
|
+
bits6 = IPAdmin.minimum_size(:IPCount => options[:IPCount], :Version => 6)
|
456
|
+
else
|
457
|
+
raise "Missing arguments: :Subnet/:IPCount"
|
458
|
+
end
|
459
|
+
else
|
460
|
+
raise "Integer or Hash expected, but #{options.class} provided."
|
350
461
|
end
|
351
462
|
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
463
|
+
list4 = []
|
464
|
+
list6 = []
|
465
|
+
dump_children(@root).each do |entry|
|
466
|
+
netstruct = entry[:NetStruct]
|
467
|
+
if (netstruct.cidr.version == 4)
|
468
|
+
if ( (netstruct.children.length == 0) && (netstruct.cidr.bits <= bits4) )
|
469
|
+
list4.push(netstruct.cidr)
|
470
|
+
end
|
356
471
|
else
|
357
|
-
|
472
|
+
if ( (netstruct.children.length == 0) && (netstruct.cidr.bits <= bits6) )
|
473
|
+
list6.push(netstruct.cidr)
|
474
|
+
end
|
358
475
|
end
|
359
476
|
end
|
360
477
|
|
361
|
-
|
362
|
-
if (
|
363
|
-
|
364
|
-
|
478
|
+
list = []
|
479
|
+
if (!version)
|
480
|
+
list.concat(list4)
|
481
|
+
list.concat(list6)
|
482
|
+
else
|
483
|
+
list.concat(list4) if (version == 4)
|
484
|
+
list.concat(list6) if (version == 6)
|
365
485
|
end
|
366
486
|
|
367
|
-
|
368
|
-
|
369
|
-
search_list.each do |entry|
|
370
|
-
depth = entry[:Depth]
|
371
|
-
net_struct = entry[:NetStruct]
|
487
|
+
return(list)
|
488
|
+
end
|
372
489
|
|
373
|
-
|
374
|
-
|
375
|
-
|
490
|
+
#======================================#
|
491
|
+
#
|
492
|
+
#======================================#
|
376
493
|
|
377
|
-
if (subnet_size >= net_struct.object.bits)
|
378
|
-
list.push(net_struct.object)
|
379
|
-
end
|
380
|
-
end
|
381
494
|
|
382
|
-
|
383
|
-
|
384
|
-
|
495
|
+
#==============================================================================#
|
496
|
+
# longest_match()
|
497
|
+
#==============================================================================#
|
385
498
|
|
499
|
+
# Find the longest matching branch of our tree to which a
|
500
|
+
# CIDR address belongs. Useful for performing 'routing table' style lookups.
|
501
|
+
#
|
502
|
+
# - Arguments:
|
503
|
+
# * CIDR address or IPAdmin::CIDR object
|
504
|
+
#
|
505
|
+
# - Returns:
|
506
|
+
# * IPAdmin::CIDR object, or nil
|
507
|
+
#
|
508
|
+
# Examples:
|
509
|
+
# longest_match = tree.longest_match('192.168.1.1')
|
510
|
+
#
|
511
|
+
def longest_match(cidr)
|
512
|
+
if ( !cidr.kind_of?(IPAdmin::CIDR) )
|
513
|
+
begin
|
514
|
+
cidr = IPAdmin::CIDR.new(:CIDR => cidr)
|
515
|
+
rescue Exception => error
|
516
|
+
raise ArgumentError, "Provided argument raised the following " +
|
517
|
+
"errors: #{error}"
|
518
|
+
end
|
386
519
|
end
|
520
|
+
|
521
|
+
found = find_me(cidr)
|
522
|
+
found = find_parent(cidr, @root) if !found
|
387
523
|
|
388
|
-
return(
|
389
|
-
|
524
|
+
return(found.cidr)
|
390
525
|
end
|
391
526
|
|
392
527
|
#======================================#
|
@@ -395,43 +530,84 @@ class Tree
|
|
395
530
|
|
396
531
|
|
397
532
|
#==============================================================================#
|
398
|
-
#
|
533
|
+
# merge_subnets!()
|
399
534
|
#==============================================================================#
|
400
535
|
|
401
|
-
#
|
402
|
-
# objects from the tree.
|
536
|
+
# Merge (summarize) all subnets of the provided CIDR address.
|
403
537
|
#
|
404
538
|
# - Arguments:
|
405
|
-
# * CIDR object
|
539
|
+
# * CIDR address or IPAdmin::CIDR object
|
406
540
|
#
|
407
541
|
# - Returns:
|
408
|
-
# * true or false
|
542
|
+
# * true on success or false on fail
|
409
543
|
#
|
410
|
-
#
|
411
|
-
#
|
544
|
+
# Examples:
|
545
|
+
# tree.merge_subnets!('192.168.1.0/24')
|
412
546
|
#
|
413
|
-
def
|
414
|
-
|
415
|
-
|
416
|
-
|
547
|
+
def merge_subnets!(cidr)
|
548
|
+
merged = false
|
549
|
+
|
550
|
+
# validate object
|
551
|
+
if ( !cidr.kind_of?(IPAdmin::CIDR) )
|
552
|
+
begin
|
553
|
+
cidr = IPAdmin::CIDR.new(:CIDR => cidr)
|
554
|
+
rescue Exception => error
|
555
|
+
raise ArgumentError, "Provided argument raised the following " +
|
556
|
+
"errors: #{error}"
|
557
|
+
end
|
417
558
|
end
|
418
559
|
|
419
|
-
|
420
|
-
|
421
|
-
|
560
|
+
me = find_me(cidr)
|
561
|
+
|
562
|
+
if (me)
|
563
|
+
to_merge = []
|
564
|
+
me.children.each {|x| to_merge.push(x.cidr)}
|
565
|
+
to_merge.each {|x| delete!(x)}
|
566
|
+
|
567
|
+
IPAdmin.merge(to_merge).each {|x| add!(x)}
|
568
|
+
merged = true
|
422
569
|
end
|
423
570
|
|
424
|
-
|
425
|
-
|
571
|
+
return(merged)
|
572
|
+
end
|
426
573
|
|
427
|
-
|
428
|
-
|
574
|
+
#======================================#
|
575
|
+
#
|
576
|
+
#======================================#
|
577
|
+
|
578
|
+
|
579
|
+
#==============================================================================#
|
580
|
+
# prune!()
|
581
|
+
#==============================================================================#
|
582
|
+
|
583
|
+
# Remove all subnets of the provided CIDR address.
|
584
|
+
#
|
585
|
+
# - Arguments:
|
586
|
+
# * CIDR address or IPAdmin::CIDR object
|
587
|
+
#
|
588
|
+
# - Returns:
|
589
|
+
# * true on success or false on fail
|
590
|
+
#
|
591
|
+
# Examples:
|
592
|
+
# did_prune = tree.prune!('192.168.1.0/24')
|
593
|
+
#
|
594
|
+
def prune!(cidr)
|
595
|
+
pruned = false
|
596
|
+
|
597
|
+
# validate object
|
598
|
+
if ( !cidr.kind_of?(IPAdmin::CIDR) )
|
599
|
+
begin
|
600
|
+
cidr = IPAdmin::CIDR.new(:CIDR => cidr)
|
601
|
+
rescue Exception => error
|
602
|
+
raise ArgumentError, "Provided argument raised the following " +
|
603
|
+
"errors: #{error}"
|
604
|
+
end
|
429
605
|
end
|
606
|
+
|
607
|
+
me = find_me(cidr)
|
430
608
|
|
431
|
-
|
432
|
-
|
433
|
-
if (home_struct.object = object)
|
434
|
-
home_branch.delete(home_struct)
|
609
|
+
if (me)
|
610
|
+
me.children.clear
|
435
611
|
pruned = true
|
436
612
|
end
|
437
613
|
|
@@ -444,57 +620,131 @@ class Tree
|
|
444
620
|
|
445
621
|
|
446
622
|
#==============================================================================#
|
447
|
-
# remove()
|
623
|
+
# remove!()
|
448
624
|
#==============================================================================#
|
449
625
|
|
450
|
-
# Remove
|
626
|
+
# Remove the provided CIDR address, and all of its subnets from the tree.
|
451
627
|
#
|
452
628
|
# - Arguments:
|
453
|
-
# * CIDR object
|
629
|
+
# * CIDR address of IPAdmin::CIDR object
|
454
630
|
#
|
455
631
|
# - Returns:
|
456
|
-
# * true or false
|
632
|
+
# * true on success or false on fail
|
457
633
|
#
|
458
|
-
#
|
459
|
-
# did_remove = tree.remove(
|
634
|
+
# Examples:
|
635
|
+
# did_remove = tree.remove!('192.168.1.0/24')
|
460
636
|
#
|
461
|
-
def remove(
|
462
|
-
|
463
|
-
|
464
|
-
|
637
|
+
def remove!(cidr)
|
638
|
+
removed = false
|
639
|
+
found = nil
|
640
|
+
|
641
|
+
# validate object
|
642
|
+
if ( !cidr.kind_of?(IPAdmin::CIDR) )
|
643
|
+
begin
|
644
|
+
cidr = IPAdmin::CIDR.new(:CIDR => cidr)
|
645
|
+
rescue Exception => error
|
646
|
+
raise ArgumentError, "Provided argument raised the following " +
|
647
|
+
"errors: #{error}"
|
648
|
+
end
|
465
649
|
end
|
466
650
|
|
467
|
-
|
468
|
-
|
469
|
-
|
651
|
+
me = find_me(cidr)
|
652
|
+
|
653
|
+
if (me)
|
654
|
+
parent = me.parent
|
655
|
+
parent.children.delete(me)
|
656
|
+
removed = true
|
470
657
|
end
|
658
|
+
|
659
|
+
return(removed)
|
660
|
+
end
|
471
661
|
|
472
|
-
|
473
|
-
|
662
|
+
#======================================#
|
663
|
+
#
|
664
|
+
#======================================#
|
474
665
|
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
666
|
+
|
667
|
+
#==============================================================================#
|
668
|
+
# resize!()
|
669
|
+
#==============================================================================#
|
670
|
+
|
671
|
+
# Resize the provided CIDR address.
|
672
|
+
#
|
673
|
+
# - Arguments:
|
674
|
+
# * CIDR address or IPAdmin::CIDR object
|
675
|
+
# * Integer representing the bits of the new netmask
|
676
|
+
#
|
677
|
+
# - Returns:
|
678
|
+
# * true on success or false on fail
|
679
|
+
#
|
680
|
+
# Examples:
|
681
|
+
# resized = tree.resize!('192.168.1.0/24', 23)
|
682
|
+
#
|
683
|
+
def resize!(cidr,bits)
|
684
|
+
resized = false
|
685
|
+
|
686
|
+
# validate cidr
|
687
|
+
if ( !cidr.kind_of?(IPAdmin::CIDR) )
|
688
|
+
begin
|
689
|
+
cidr = IPAdmin::CIDR.new(:CIDR => cidr)
|
690
|
+
rescue Exception => error
|
691
|
+
raise ArgumentError, "Provided argument raised the following " +
|
692
|
+
"errors: #{error}"
|
491
693
|
end
|
694
|
+
end
|
492
695
|
|
493
|
-
|
494
|
-
|
696
|
+
me = find_me(cidr)
|
697
|
+
|
698
|
+
if (me)
|
699
|
+
new = me.cidr.resize(bits)
|
700
|
+
delete!(me.cidr)
|
701
|
+
add!(new)
|
702
|
+
resized = true
|
495
703
|
end
|
704
|
+
|
705
|
+
return(resized)
|
706
|
+
end
|
496
707
|
|
497
|
-
|
708
|
+
#======================================#
|
709
|
+
#
|
710
|
+
#======================================#
|
711
|
+
|
712
|
+
|
713
|
+
#==============================================================================#
|
714
|
+
# root()
|
715
|
+
#==============================================================================#
|
716
|
+
|
717
|
+
# Returns the root of the provided CIDR address.
|
718
|
+
#
|
719
|
+
# - Arguments:
|
720
|
+
# * CIDR address or IPAdmin::CIDR object
|
721
|
+
#
|
722
|
+
# - Returns:
|
723
|
+
# * IPAdmin::CIDR object
|
724
|
+
#
|
725
|
+
# Examples:
|
726
|
+
# puts tree.root('192.168.1.32/27')
|
727
|
+
#
|
728
|
+
def root(cidr)
|
729
|
+
# validate object
|
730
|
+
if ( !cidr.kind_of?(IPAdmin::CIDR) )
|
731
|
+
begin
|
732
|
+
cidr = IPAdmin::CIDR.new(:CIDR => cidr)
|
733
|
+
rescue Exception => error
|
734
|
+
raise ArgumentError, "Provided argument raised the following " +
|
735
|
+
"errors: #{error}"
|
736
|
+
end
|
737
|
+
end
|
738
|
+
|
739
|
+
parent = find_parent(cidr,@root)
|
740
|
+
|
741
|
+
if (parent && parent != @root)
|
742
|
+
until (parent.parent == @root)
|
743
|
+
parent = parent.parent
|
744
|
+
end
|
745
|
+
end
|
746
|
+
|
747
|
+
return(parent.cidr)
|
498
748
|
end
|
499
749
|
|
500
750
|
#======================================#
|
@@ -514,21 +764,16 @@ class Tree
|
|
514
764
|
# - Returns:
|
515
765
|
# * String representing the contents of the tree
|
516
766
|
#
|
517
|
-
#
|
767
|
+
# Examples:
|
518
768
|
# puts tree.show()
|
519
769
|
#
|
520
770
|
def show()
|
521
771
|
printed = ""
|
522
|
-
list =
|
772
|
+
list = dump_children(@root)
|
523
773
|
|
524
774
|
list.each do |entry|
|
525
|
-
|
775
|
+
cidr = entry[:NetStruct].cidr
|
526
776
|
depth = entry[:Depth]
|
527
|
-
network = IPAdmin.unpack_ip_addr(:Integer => net_struct.network,
|
528
|
-
:Version => @version)
|
529
|
-
netmask = IPAdmin.unpack_ip_netmask(:Integer => net_struct.netmask,
|
530
|
-
:Version => @version)
|
531
|
-
network = IPAdmin.shorten(network) if (@version == 6)
|
532
777
|
|
533
778
|
if (depth == 0)
|
534
779
|
indent = ""
|
@@ -536,7 +781,7 @@ class Tree
|
|
536
781
|
indent = " " * (depth*3)
|
537
782
|
end
|
538
783
|
|
539
|
-
printed << "#{indent}#{
|
784
|
+
printed << "#{indent}#{cidr.desc(:Short => true)}\n"
|
540
785
|
end
|
541
786
|
|
542
787
|
return(printed)
|
@@ -547,45 +792,40 @@ class Tree
|
|
547
792
|
#======================================#
|
548
793
|
|
549
794
|
|
550
|
-
|
551
|
-
|
552
|
-
# PRIVATE METHODS
|
553
|
-
private
|
554
|
-
|
555
795
|
#==============================================================================#
|
556
|
-
#
|
796
|
+
# siblings()
|
557
797
|
#==============================================================================#
|
558
798
|
|
559
|
-
#
|
799
|
+
# Return list of the sibling CIDRs of the provided CIDR address.
|
560
800
|
#
|
561
801
|
# - Arguments:
|
562
|
-
# *
|
802
|
+
# * CIDR address or IPAdmin::CIDR object
|
563
803
|
#
|
564
804
|
# - Returns:
|
565
|
-
# *
|
805
|
+
# * Array of IPAdmin::CIDR objects
|
566
806
|
#
|
567
|
-
#
|
568
|
-
#
|
807
|
+
# Examples:
|
808
|
+
# puts tree.siblings('192.168.1.0/27')
|
569
809
|
#
|
570
|
-
def
|
571
|
-
#
|
572
|
-
if (!
|
573
|
-
|
574
|
-
|
575
|
-
|
810
|
+
def siblings(cidr)
|
811
|
+
# validate object
|
812
|
+
if ( !cidr.kind_of?(IPAdmin::CIDR) )
|
813
|
+
begin
|
814
|
+
cidr = IPAdmin::CIDR.new(:CIDR => cidr)
|
815
|
+
rescue Exception => error
|
816
|
+
raise ArgumentError, "Provided argument raised the following " +
|
817
|
+
"errors: #{error}"
|
818
|
+
end
|
576
819
|
end
|
577
820
|
|
578
|
-
|
579
|
-
|
580
|
-
if(
|
581
|
-
|
821
|
+
list = []
|
822
|
+
find_parent(cidr,@root).children.each do |entry|
|
823
|
+
if (!IPAdmin.compare(cidr,entry.cidr))
|
824
|
+
list.push(entry.cidr)
|
582
825
|
end
|
583
|
-
index += 1
|
584
826
|
end
|
585
827
|
|
586
|
-
|
587
|
-
|
588
|
-
return()
|
828
|
+
return(list)
|
589
829
|
end
|
590
830
|
|
591
831
|
#======================================#
|
@@ -594,50 +834,54 @@ private
|
|
594
834
|
|
595
835
|
|
596
836
|
#==============================================================================#
|
597
|
-
#
|
837
|
+
# supernets()
|
598
838
|
#==============================================================================#
|
599
839
|
|
600
|
-
#
|
840
|
+
# Return list of the top-level supernets of this tree.
|
601
841
|
#
|
602
842
|
# - Arguments:
|
603
|
-
# *
|
843
|
+
# * none
|
604
844
|
#
|
605
845
|
# - Returns:
|
606
|
-
# *
|
846
|
+
# * Array of IPAdmin::CIDR objects
|
607
847
|
#
|
608
|
-
#
|
609
|
-
#
|
848
|
+
# Examples:
|
849
|
+
# supernets = tree.supernets()
|
610
850
|
#
|
611
|
-
def
|
851
|
+
def supernets()
|
852
|
+
supernets = []
|
853
|
+
@root.children.each {|x| supernets.push(x.cidr)}
|
854
|
+
return (supernets)
|
855
|
+
end
|
612
856
|
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
raise ArgumentError, "Incorrect argument types " +
|
617
|
-
"#{struct1.class} and #{struct2.class}."
|
618
|
-
end
|
857
|
+
#======================================#
|
858
|
+
#
|
859
|
+
#======================================#
|
619
860
|
|
620
|
-
network1 = struct1.network
|
621
|
-
netmask1 = struct1.netmask
|
622
|
-
network2 = struct2.network
|
623
|
-
netmask2 = struct2.netmask
|
624
|
-
hostmask1 = netmask1 ^ @all_f
|
625
861
|
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
862
|
+
|
863
|
+
|
864
|
+
# PRIVATE INSTANCE METHODS
|
865
|
+
private
|
866
|
+
|
867
|
+
#==============================================================================#
|
868
|
+
# add_to_parent() private
|
869
|
+
#==============================================================================#
|
870
|
+
|
871
|
+
# Add NetStruct object to an array of NetStruct's
|
872
|
+
#
|
873
|
+
def add_to_parent(new_entry, parent)
|
874
|
+
index = 0
|
875
|
+
parent.children.each do
|
876
|
+
if(new_entry.cidr.packed_network < parent.children[index].cidr.packed_network)
|
877
|
+
break
|
637
878
|
end
|
879
|
+
index += 1
|
638
880
|
end
|
639
881
|
|
640
|
-
|
882
|
+
parent.children.insert(index, new_entry)
|
883
|
+
|
884
|
+
return()
|
641
885
|
end
|
642
886
|
|
643
887
|
#======================================#
|
@@ -646,32 +890,21 @@ private
|
|
646
890
|
|
647
891
|
|
648
892
|
#==============================================================================#
|
649
|
-
#
|
893
|
+
# dump_children() private
|
650
894
|
#==============================================================================#
|
651
895
|
|
652
896
|
# Dump contents of an Array of NetStruct objects
|
653
897
|
#
|
654
|
-
|
655
|
-
# * array of NetStruct objects, and an optional depth within the tree
|
656
|
-
#
|
657
|
-
# - Returns:
|
658
|
-
# * array of hashes in form: :NetStruct => IPAdmin::NetStruct object
|
659
|
-
# :Depth => (depth level in tree)
|
660
|
-
# Example:
|
661
|
-
# dumped = dump_branch(branch)
|
662
|
-
#
|
663
|
-
def dump_branch(branch,depth=nil)
|
898
|
+
def dump_children(parent,depth=nil)
|
664
899
|
list = []
|
665
900
|
depth = 0 if (!depth)
|
666
901
|
|
667
|
-
|
668
|
-
subnets = entry.subnets
|
902
|
+
parent.children.each do |entry|
|
669
903
|
list.push({:NetStruct => entry, :Depth => depth})
|
670
904
|
|
671
|
-
if (
|
672
|
-
list.concat(
|
905
|
+
if (entry.children.length > 0)
|
906
|
+
list.concat( dump_children(entry, (depth+1) ) )
|
673
907
|
end
|
674
|
-
|
675
908
|
end
|
676
909
|
|
677
910
|
return(list)
|
@@ -683,46 +916,55 @@ private
|
|
683
916
|
|
684
917
|
|
685
918
|
#==============================================================================#
|
686
|
-
#
|
919
|
+
# find_me() private
|
687
920
|
#==============================================================================#
|
688
921
|
|
689
|
-
# Find the
|
690
|
-
#
|
691
|
-
# - Arguments:
|
692
|
-
# * IPAdmin::NetStruct to find, and Array of
|
693
|
-
# IPAdmin::NetStruct's to search
|
694
|
-
#
|
695
|
-
# - Returns:
|
696
|
-
# * array of: container IPAdmin::NetStruct object,
|
697
|
-
# and container branch, or nil
|
922
|
+
# Find the NetStruct to which a cidr belongs.
|
698
923
|
#
|
699
|
-
|
700
|
-
|
924
|
+
def find_me(cidr)
|
925
|
+
me = nil
|
926
|
+
|
927
|
+
# find matching
|
928
|
+
parent = find_parent(cidr,@root)
|
929
|
+
parent.children.each do |entry|
|
930
|
+
if (entry.cidr.version == cidr.version)
|
931
|
+
if (IPAdmin.compare(entry.cidr,cidr) == 1)
|
932
|
+
me = entry
|
933
|
+
break
|
934
|
+
end
|
935
|
+
end
|
936
|
+
end
|
937
|
+
|
938
|
+
return(me)
|
939
|
+
end
|
940
|
+
|
941
|
+
#======================================#
|
701
942
|
#
|
702
|
-
|
703
|
-
ret_val = nil
|
943
|
+
#======================================#
|
704
944
|
|
705
|
-
branch.each do |entry|
|
706
|
-
is_contained = contains(entry,net_struct)
|
707
945
|
|
708
|
-
|
709
|
-
|
710
|
-
|
946
|
+
#==============================================================================#
|
947
|
+
# find_parent() private
|
948
|
+
#==============================================================================#
|
711
949
|
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
home_branch = search_results[1]
|
717
|
-
end
|
718
|
-
end
|
950
|
+
# Find the parent NetStruct to which a child NetStruct belongs.
|
951
|
+
#
|
952
|
+
def find_parent(cidr,parent)
|
953
|
+
version = cidr.version
|
719
954
|
|
720
|
-
|
955
|
+
parent.children.each do |entry|
|
956
|
+
if (entry.cidr.version == version && entry.cidr.contains?(cidr))
|
957
|
+
parent = entry
|
958
|
+
|
959
|
+
if (parent.children.length > 0)
|
960
|
+
search_results = find_parent(cidr,parent)
|
961
|
+
parent = search_results if (search_results)
|
962
|
+
end
|
721
963
|
break
|
722
964
|
end
|
723
965
|
end
|
724
966
|
|
725
|
-
return(
|
967
|
+
return(parent)
|
726
968
|
end
|
727
969
|
|
728
970
|
#======================================#
|