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