netaddr 1.2.0 → 1.3.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/changelog +14 -6
- data/lib/cidr.rb +497 -225
- data/lib/cidr_shortcuts.rb +21 -21
- data/lib/eui.rb +162 -133
- data/lib/ip_math.rb +45 -27
- data/lib/methods.rb +187 -178
- data/lib/{net_addr.rb → netaddr.rb} +3 -1
- data/lib/tree.rb +87 -52
- data/lib/validation_shortcuts.rb +10 -10
- data/tests/cidr_test.rb +253 -167
- data/tests/eui_test.rb +39 -25
- data/tests/methods_test.rb +100 -118
- data/tests/tree_test.rb +99 -56
- metadata +12 -12
@@ -1,9 +1,11 @@
|
|
1
1
|
=begin rdoc
|
2
|
-
Copyleft (c) 2006 Dustin Spinhirne
|
2
|
+
Copyleft (c) 2006 Dustin Spinhirne
|
3
3
|
|
4
4
|
Licensed under the same terms as Ruby, No Warranty is provided.
|
5
5
|
=end
|
6
6
|
|
7
|
+
require 'time'
|
8
|
+
require 'digest/sha1'
|
7
9
|
require File.join(File.dirname(__FILE__), 'validation_shortcuts.rb')
|
8
10
|
require File.join(File.dirname(__FILE__), 'ip_math.rb')
|
9
11
|
require File.join(File.dirname(__FILE__), 'cidr_shortcuts.rb')
|
data/lib/tree.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
=begin rdoc
|
2
|
-
Copyleft (c) 2006 Dustin Spinhirne
|
2
|
+
Copyleft (c) 2006 Dustin Spinhirne
|
3
3
|
|
4
4
|
Licensed under the same terms as Ruby, No Warranty is provided.
|
5
5
|
=end
|
@@ -10,7 +10,7 @@ module NetAddr
|
|
10
10
|
#
|
11
11
|
#A class & series of methods for creating and manipulating IP-based
|
12
12
|
#heirarchical trees. Both IPv4 and IPv6 are supported.
|
13
|
-
#
|
13
|
+
#
|
14
14
|
#A sample tree would look like:
|
15
15
|
# 192.168.1.0/24
|
16
16
|
# 192.168.1.0/26
|
@@ -36,7 +36,8 @@ class Tree
|
|
36
36
|
#===Synopsis
|
37
37
|
#Create a new Tree object.
|
38
38
|
#
|
39
|
-
#
|
39
|
+
# Example:
|
40
|
+
# NetAddr::Tree.new()
|
40
41
|
#
|
41
42
|
#===Arguments:
|
42
43
|
#* none
|
@@ -53,9 +54,9 @@ class Tree
|
|
53
54
|
|
54
55
|
#===Synopsis
|
55
56
|
# Add a CIDR address or NetAddr::CIDR object to the tree.
|
56
|
-
#
|
57
|
+
# Example:
|
57
58
|
# tree.add!('192.168.1.0/24')
|
58
|
-
# cidr = NetAddr::CIDR.create(
|
59
|
+
# cidr = NetAddr::CIDR.create('192.168.1.0/24', :Tag => {:title => 'test net'}
|
59
60
|
# tree.add!(cidr)
|
60
61
|
#
|
61
62
|
#===Arguments:
|
@@ -90,7 +91,8 @@ class Tree
|
|
90
91
|
#===Synopsis
|
91
92
|
# Returns all the ancestors of the provided CIDR addresses.
|
92
93
|
#
|
93
|
-
#
|
94
|
+
# Example:
|
95
|
+
# tree.ancestors('192.168.1.0/27')
|
94
96
|
#
|
95
97
|
#===Arguments:
|
96
98
|
#* String or NetAddr::CIDR object
|
@@ -112,7 +114,7 @@ class Tree
|
|
112
114
|
list = []
|
113
115
|
parent = find_parent(cidr)
|
114
116
|
until (!parent.tag[:Parent])
|
115
|
-
list.push(parent)
|
117
|
+
list.push( NetAddr.cidr_build(parent.version, parent.to_i(:network), parent.to_i(:netmask)) )
|
116
118
|
parent = parent.tag[:Parent]
|
117
119
|
end
|
118
120
|
|
@@ -126,7 +128,8 @@ class Tree
|
|
126
128
|
#===Synopsis
|
127
129
|
# Returns all the immediate children of the provided CIDR addresses.
|
128
130
|
#
|
129
|
-
#
|
131
|
+
# Example:
|
132
|
+
# tree.children('192.168.1.0/24')
|
130
133
|
#
|
131
134
|
#===Arguments:
|
132
135
|
#* String or NetAddr::CIDR object
|
@@ -147,7 +150,11 @@ class Tree
|
|
147
150
|
|
148
151
|
list = []
|
149
152
|
me = find_me(cidr)
|
150
|
-
|
153
|
+
if (me)
|
154
|
+
me.tag[:Subnets].each do |child|
|
155
|
+
list.push( NetAddr.cidr_build(child.version, child.to_i(:network), child.to_i(:netmask)) )
|
156
|
+
end
|
157
|
+
end
|
151
158
|
|
152
159
|
return(list)
|
153
160
|
end
|
@@ -159,7 +166,8 @@ class Tree
|
|
159
166
|
#===Synopsis
|
160
167
|
# Return all descendants of the provided CIDR address.
|
161
168
|
#
|
162
|
-
#
|
169
|
+
# Example:
|
170
|
+
# tree.descendants('192.168.1.0/24')
|
163
171
|
#
|
164
172
|
#===Arguments:
|
165
173
|
#* String or NetAddr::CIDR object
|
@@ -181,7 +189,12 @@ class Tree
|
|
181
189
|
end
|
182
190
|
|
183
191
|
me = find_me(cidr)
|
184
|
-
|
192
|
+
if (me)
|
193
|
+
dump_children(me).each do |x|
|
194
|
+
child = x[:CIDR]
|
195
|
+
list.push( NetAddr.cidr_build(child.version, child.to_i(:network), child.to_i(:netmask)) )
|
196
|
+
end
|
197
|
+
end
|
185
198
|
|
186
199
|
return(list)
|
187
200
|
end
|
@@ -193,7 +206,8 @@ class Tree
|
|
193
206
|
#===Synopsis
|
194
207
|
# Remove the provided CIDR address from the tree.
|
195
208
|
#
|
196
|
-
#
|
209
|
+
# Example:
|
210
|
+
# tree.remove!('192.168.1.0/24')
|
197
211
|
#
|
198
212
|
#===Arguments:
|
199
213
|
#* String or NetAddr::CIDR object
|
@@ -220,7 +234,7 @@ class Tree
|
|
220
234
|
# remove
|
221
235
|
if (me)
|
222
236
|
parent = me.tag[:Parent]
|
223
|
-
children = me.tag[:Subnets]
|
237
|
+
children = me.tag[:Subnets]
|
224
238
|
parent.tag[:Subnets].delete(me)
|
225
239
|
children.each {|x| add_to_parent(x,parent)}
|
226
240
|
removed = true
|
@@ -236,7 +250,8 @@ class Tree
|
|
236
250
|
#===Synopsis
|
237
251
|
# Dump the contents of this tree.
|
238
252
|
#
|
239
|
-
#
|
253
|
+
# Example:
|
254
|
+
# tree.dump()
|
240
255
|
#
|
241
256
|
#===Arguments:
|
242
257
|
#* none
|
@@ -249,6 +264,7 @@ class Tree
|
|
249
264
|
def dump()
|
250
265
|
list = dump_children(@v4_root)
|
251
266
|
list.concat( dump_children(@v6_root) )
|
267
|
+
list.each {|x| x[:CIDR] = NetAddr.cidr_build(x[:CIDR].version, x[:CIDR].to_i(:network), x[:CIDR].to_i(:netmask)) }
|
252
268
|
return(list)
|
253
269
|
end
|
254
270
|
|
@@ -259,7 +275,8 @@ class Tree
|
|
259
275
|
#===Synopsis
|
260
276
|
# Has a CIDR address already been added to the tree?
|
261
277
|
#
|
262
|
-
#
|
278
|
+
# Example:
|
279
|
+
# tree.exists?('192.168.1.0/24')
|
263
280
|
#
|
264
281
|
#===Arguments:
|
265
282
|
#* String or NetAddr::CIDR object
|
@@ -291,7 +308,8 @@ class Tree
|
|
291
308
|
#===Synopsis
|
292
309
|
# Fill in the missing subnets of a particular CIDR.
|
293
310
|
#
|
294
|
-
#
|
311
|
+
# Example:
|
312
|
+
# tree.fill_in!('192.168.1.0/24')
|
295
313
|
#
|
296
314
|
#===Arguments:
|
297
315
|
#* String or NetAddr::CIDR object
|
@@ -315,6 +333,9 @@ class Tree
|
|
315
333
|
me = find_me(cidr)
|
316
334
|
if (me && me.tag[:Subnets].length != 0)
|
317
335
|
me.tag[:Subnets] = NetAddr.cidr_fill_in(me, me.tag[:Subnets])
|
336
|
+
me.tag[:Subnets].each do |subnet|
|
337
|
+
subnet.tag[:Subnets] = [] if (!subnet.tag.has_key?(:Subnets))
|
338
|
+
end
|
318
339
|
filled = true
|
319
340
|
end
|
320
341
|
return(filled)
|
@@ -327,7 +348,8 @@ class Tree
|
|
327
348
|
#===Synopsis
|
328
349
|
# Find and return a CIDR from within the tree.
|
329
350
|
#
|
330
|
-
#
|
351
|
+
# Example:
|
352
|
+
# tree.find('192.168.1.0/24')
|
331
353
|
#
|
332
354
|
#===Arguments:
|
333
355
|
#* String or NetAddr::CIDR object
|
@@ -338,14 +360,19 @@ class Tree
|
|
338
360
|
def find(cidr)
|
339
361
|
if ( !cidr.kind_of?(NetAddr::CIDR) )
|
340
362
|
begin
|
341
|
-
cidr = NetAddr::CIDR.create(
|
363
|
+
cidr = NetAddr::CIDR.create(cidr)
|
342
364
|
rescue Exception => error
|
343
365
|
raise ArgumentError, "Provided argument raised the following " +
|
344
366
|
"errors: #{error}"
|
345
367
|
end
|
346
368
|
end
|
347
369
|
|
348
|
-
|
370
|
+
me = find_me(cidr)
|
371
|
+
if (me)
|
372
|
+
me = NetAddr.cidr_build(me.version, me.to_i(:network), me.to_i(:netmask))
|
373
|
+
end
|
374
|
+
|
375
|
+
return(me)
|
349
376
|
end
|
350
377
|
|
351
378
|
#==============================================================================#
|
@@ -356,7 +383,8 @@ class Tree
|
|
356
383
|
# Find subnets that are of at least size X. Only subnets that are not themselves
|
357
384
|
# subnetted will be returned. :Subnet takes precedence over :IPCount
|
358
385
|
#
|
359
|
-
#
|
386
|
+
# Example:
|
387
|
+
# tree.find_space(:IPCount => 16)
|
360
388
|
#
|
361
389
|
#===Arguments:
|
362
390
|
#* Minimum subnet size in bits, or a Hash with the following keys:
|
@@ -412,7 +440,10 @@ class Tree
|
|
412
440
|
end
|
413
441
|
end
|
414
442
|
|
415
|
-
|
443
|
+
new_list = []
|
444
|
+
list.each {|x| new_list.push( NetAddr.cidr_build(x.version, x.to_i(:network), x.to_i(:netmask)) )}
|
445
|
+
|
446
|
+
return(new_list)
|
416
447
|
end
|
417
448
|
|
418
449
|
#==============================================================================#
|
@@ -423,7 +454,8 @@ class Tree
|
|
423
454
|
#Find the longest matching branch of our tree to which a
|
424
455
|
#CIDR address belongs. Useful for performing 'routing table' style lookups.
|
425
456
|
#
|
426
|
-
#
|
457
|
+
# Example:
|
458
|
+
# tree.longest_match('192.168.1.1')
|
427
459
|
#
|
428
460
|
#===Arguments:
|
429
461
|
#* String or NetAddr::CIDR object
|
@@ -444,7 +476,7 @@ class Tree
|
|
444
476
|
found = find_me(cidr)
|
445
477
|
found = find_parent(cidr) if !found
|
446
478
|
|
447
|
-
return(found)
|
479
|
+
return( NetAddr.cidr_build(found.version, found.to_i(:network), found.to_i(:netmask)) )
|
448
480
|
end
|
449
481
|
|
450
482
|
#==============================================================================#
|
@@ -454,7 +486,8 @@ class Tree
|
|
454
486
|
#===Synopsis
|
455
487
|
# Remove all subnets of the provided CIDR address.
|
456
488
|
#
|
457
|
-
#
|
489
|
+
# Example:
|
490
|
+
# tree.prune!('192.168.1.0/24')
|
458
491
|
#
|
459
492
|
#===Arguments:
|
460
493
|
#* String or NetAddr::CIDR object
|
@@ -468,7 +501,7 @@ class Tree
|
|
468
501
|
# validate object
|
469
502
|
if ( !cidr.kind_of?(NetAddr::CIDR) )
|
470
503
|
begin
|
471
|
-
cidr = NetAddr::CIDR.create(
|
504
|
+
cidr = NetAddr::CIDR.create(cidr)
|
472
505
|
rescue Exception => error
|
473
506
|
raise ArgumentError, "Provided argument raised the following " +
|
474
507
|
"errors: #{error}"
|
@@ -492,7 +525,8 @@ class Tree
|
|
492
525
|
#===Synopsis
|
493
526
|
# Remove the provided CIDR address, and all of its subnets from the tree.
|
494
527
|
#
|
495
|
-
#
|
528
|
+
# Example:
|
529
|
+
# tree.remove!('192.168.1.0/24')
|
496
530
|
#
|
497
531
|
#===Arguments:
|
498
532
|
#* String or NetAddr::CIDR object
|
@@ -507,7 +541,7 @@ class Tree
|
|
507
541
|
# validate object
|
508
542
|
if ( !cidr.kind_of?(NetAddr::CIDR) )
|
509
543
|
begin
|
510
|
-
cidr = NetAddr::CIDR.create(
|
544
|
+
cidr = NetAddr::CIDR.create(cidr)
|
511
545
|
rescue Exception => error
|
512
546
|
raise ArgumentError, "Provided argument raised the following " +
|
513
547
|
"errors: #{error}"
|
@@ -532,7 +566,8 @@ class Tree
|
|
532
566
|
#===Synopsis
|
533
567
|
# Resize the provided CIDR address.
|
534
568
|
#
|
535
|
-
#
|
569
|
+
# Example:
|
570
|
+
# tree.resize!('192.168.1.0/24', 23)
|
536
571
|
#
|
537
572
|
#===Arguments:
|
538
573
|
#* CIDR address as a String or an NetAddr::CIDR object
|
@@ -547,7 +582,7 @@ class Tree
|
|
547
582
|
# validate cidr
|
548
583
|
if ( !cidr.kind_of?(NetAddr::CIDR) )
|
549
584
|
begin
|
550
|
-
cidr = NetAddr::CIDR.create(
|
585
|
+
cidr = NetAddr::CIDR.create(cidr)
|
551
586
|
rescue Exception => error
|
552
587
|
raise ArgumentError, "Provided argument raised the following " +
|
553
588
|
"errors: #{error}"
|
@@ -573,7 +608,8 @@ class Tree
|
|
573
608
|
#===Synopsis
|
574
609
|
# Returns the root of the provided CIDR address.
|
575
610
|
#
|
576
|
-
#
|
611
|
+
# Example:
|
612
|
+
# tree.root('192.168.1.32/27')
|
577
613
|
#
|
578
614
|
#===Arguments:
|
579
615
|
#* String or NetAddr::CIDR object
|
@@ -601,7 +637,7 @@ class Tree
|
|
601
637
|
end
|
602
638
|
end
|
603
639
|
|
604
|
-
return(parent)
|
640
|
+
return( NetAddr.cidr_build(parent.version, parent.to_i(:network), parent.to_i(:netmask)) )
|
605
641
|
end
|
606
642
|
|
607
643
|
#==============================================================================#
|
@@ -609,9 +645,10 @@ class Tree
|
|
609
645
|
#==============================================================================#
|
610
646
|
|
611
647
|
#===Synopsis
|
612
|
-
# Print the tree as a
|
648
|
+
# Print the tree as a formatted string.
|
613
649
|
#
|
614
|
-
#
|
650
|
+
# Example:
|
651
|
+
# tree.show()
|
615
652
|
#
|
616
653
|
#===Arguments:
|
617
654
|
#* none
|
@@ -662,7 +699,8 @@ class Tree
|
|
662
699
|
#===Synopsis
|
663
700
|
# Return list of the sibling CIDRs of the provided CIDR address.
|
664
701
|
#
|
665
|
-
#
|
702
|
+
# Example:
|
703
|
+
# tree.siblings('192.168.1.0/27')
|
666
704
|
#
|
667
705
|
#===Arguments:
|
668
706
|
#* String or NetAddr::CIDR object
|
@@ -684,7 +722,7 @@ class Tree
|
|
684
722
|
list = []
|
685
723
|
find_parent(cidr).tag[:Subnets].each do |entry|
|
686
724
|
if (!cidr.cmp(entry))
|
687
|
-
list.push(entry)
|
725
|
+
list.push( NetAddr.cidr_build(entry.version, entry.to_i(:network), entry.to_i(:netmask)) )
|
688
726
|
end
|
689
727
|
end
|
690
728
|
|
@@ -699,6 +737,7 @@ class Tree
|
|
699
737
|
# Summarize all subnets of the provided CIDR address. The subnets will be
|
700
738
|
# placed under the new summary address within the tree.
|
701
739
|
#
|
740
|
+
# Example:
|
702
741
|
# tree.summarize_subnets!('192.168.1.0/24')
|
703
742
|
#
|
704
743
|
#===Arguments:
|
@@ -739,7 +778,8 @@ class Tree
|
|
739
778
|
#===Synopsis
|
740
779
|
# Return list of the top-level supernets of this tree.
|
741
780
|
#
|
742
|
-
#
|
781
|
+
# Example:
|
782
|
+
# tree.supernets()
|
743
783
|
#
|
744
784
|
#===Arguments:
|
745
785
|
#* none
|
@@ -749,8 +789,8 @@ class Tree
|
|
749
789
|
#
|
750
790
|
def supernets()
|
751
791
|
supernets = []
|
752
|
-
@v4_root.tag[:Subnets].each {|x| supernets.push(x)}
|
753
|
-
@v6_root.tag[:Subnets].each {|x| supernets.push(x)}
|
792
|
+
@v4_root.tag[:Subnets].each {|x| supernets.push( NetAddr.cidr_build(x.version, x.to_i(:network), x.to_i(:netmask)) )}
|
793
|
+
@v6_root.tag[:Subnets].each {|x| supernets.push( NetAddr.cidr_build(x.version, x.to_i(:network), x.to_i(:netmask)) )}
|
754
794
|
return (supernets)
|
755
795
|
end
|
756
796
|
|
@@ -770,19 +810,20 @@ private
|
|
770
810
|
|
771
811
|
if (!duplicate)
|
772
812
|
# check parent for subnets of cidr
|
773
|
-
|
774
|
-
|
775
|
-
old_cidr = parent.tag[:Subnets]
|
813
|
+
new_parent_subs = []
|
814
|
+
parent.tag[:Subnets].length.times do
|
815
|
+
old_cidr = parent.tag[:Subnets].shift
|
776
816
|
cmp = NetAddr.cidr_compare(cidr, old_cidr)
|
777
817
|
if (cmp && cmp == 1)
|
778
818
|
old_cidr.tag[:Parent] = cidr
|
779
819
|
cidr.tag[:Subnets].push(old_cidr)
|
780
|
-
|
820
|
+
else
|
821
|
+
new_parent_subs.push(old_cidr)
|
781
822
|
end
|
782
823
|
end
|
783
824
|
|
784
825
|
cidr.tag[:Parent] = parent
|
785
|
-
parent.tag[:Subnets]
|
826
|
+
parent.tag[:Subnets] = new_parent_subs
|
786
827
|
parent.tag[:Subnets].push(cidr)
|
787
828
|
parent.tag[:Subnets] = NetAddr.cidr_sort(parent.tag[:Subnets])
|
788
829
|
end
|
@@ -797,12 +838,8 @@ private
|
|
797
838
|
# Add CIDR to a Tree
|
798
839
|
#
|
799
840
|
def add_to_tree(cidr,root=nil)
|
800
|
-
|
801
|
-
# find cidr's parent
|
802
841
|
parent = find_parent(cidr)
|
803
|
-
|
804
|
-
add_to_parent(cidr,parent)
|
805
|
-
end
|
842
|
+
add_to_parent(cidr,parent)
|
806
843
|
|
807
844
|
return(nil)
|
808
845
|
end
|
@@ -813,9 +850,8 @@ private
|
|
813
850
|
|
814
851
|
# Dump contents of an Array of NetStruct objects
|
815
852
|
#
|
816
|
-
def dump_children(parent,depth=
|
853
|
+
def dump_children(parent,depth=0)
|
817
854
|
list = []
|
818
|
-
depth = 0 if (!depth)
|
819
855
|
|
820
856
|
parent.tag[:Subnets].each do |entry|
|
821
857
|
list.push({:CIDR => entry, :Depth => depth})
|
@@ -867,8 +903,7 @@ private
|
|
867
903
|
end
|
868
904
|
bit_diff = cidr.bits - parent.bits
|
869
905
|
|
870
|
-
# if
|
871
|
-
# if not then check to make sure that one of the children is the actual parent.
|
906
|
+
# if bit_diff greater than 1 bit then check if one of the children is the actual parent.
|
872
907
|
if (bit_diff > 1 && parent.tag[:Subnets].length != 0)
|
873
908
|
list = parent.tag[:Subnets]
|
874
909
|
found = NetAddr.cidr_find_in_list(cidr,list)
|
data/lib/validation_shortcuts.rb
CHANGED
@@ -132,17 +132,17 @@ module_function :validate_ip_str
|
|
132
132
|
#==============================================================================#
|
133
133
|
# validate_netmask_int()
|
134
134
|
#==============================================================================#
|
135
|
-
def validate_netmask_int(netmask,version,
|
135
|
+
def validate_netmask_int(netmask,version,is_int=false)
|
136
136
|
address_len = 32
|
137
137
|
address_len = 128 if (version == 6)
|
138
138
|
|
139
|
-
if (!
|
139
|
+
if (!is_int)
|
140
140
|
if (netmask > address_len || netmask < 0 )
|
141
141
|
raise ValidationError, "Netmask, #{netmask}, is out of bounds for IPv#{version}."
|
142
142
|
end
|
143
143
|
else
|
144
144
|
if (netmask >= 2**address_len || netmask < 0 )
|
145
|
-
raise ValidationError, "
|
145
|
+
raise ValidationError, "netmask (#{netmask}) is out of bounds for IPv#{version}."
|
146
146
|
end
|
147
147
|
end
|
148
148
|
return(true)
|
@@ -158,27 +158,27 @@ def validate_netmask_str(netmask,version)
|
|
158
158
|
|
159
159
|
if(netmask =~ /\./) # extended netmask
|
160
160
|
all_f = 2**32-1
|
161
|
-
|
161
|
+
netmask_int = 0
|
162
162
|
|
163
163
|
# validate & pack extended mask
|
164
164
|
begin
|
165
|
-
|
165
|
+
netmask_int = NetAddr.ip_to_i(netmask, :Version => 4)
|
166
166
|
rescue Exception => error
|
167
167
|
raise ValidationError, "#{netmask} is improperly formed: #{error}"
|
168
168
|
end
|
169
169
|
|
170
170
|
# cycle through the bits of hostmask and compare
|
171
|
-
# with
|
172
|
-
#
|
173
|
-
#
|
171
|
+
# with netmask_int. when we hit the firt '1' within
|
172
|
+
# netmask_int (our netmask boundary), xor hostmask and
|
173
|
+
# netmask_int. the result should be all 1's. this whole
|
174
174
|
# process is in place to make sure that we dont have
|
175
175
|
# and crazy masks such as 255.254.255.0
|
176
176
|
hostmask = 1
|
177
177
|
32.times do
|
178
|
-
check =
|
178
|
+
check = netmask_int & hostmask
|
179
179
|
if ( check != 0)
|
180
180
|
hostmask = hostmask >> 1
|
181
|
-
unless ( (
|
181
|
+
unless ( (netmask_int ^ hostmask) == all_f)
|
182
182
|
raise ValidationError, "#{netmask} contains '1' bits within the host portion of the netmask."
|
183
183
|
end
|
184
184
|
break
|