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.

@@ -1,9 +1,11 @@
1
1
  =begin rdoc
2
- Copyleft (c) 2006 Dustin Spinhirne (www.spinhirne.com)
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 (www.spinhirne.com)
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
- # tree = NetAddr::Tree.new()
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(:CIDR => '192.168.1.0/24', :Tag => {:title => 'test net'}
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
- # puts tree.ancestors('192.168.1.0/27')
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
- # puts tree.children('192.168.1.0/24')
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
- me.tag[:Subnets].each {|child| list.push(child) } if (me)
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
- # descendants = tree.descendants('192.168.1.0/24')
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
- dump_children(me).each {|x| list.push(x[:CIDR])} if (me)
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
- # did_remove = tree.remove!('192.168.1.0/24')
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
- # dumped = tree.dump()
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
- # added = tree.exists?('192.168.1.0/24')
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
- # success = tree.fill_in!('192.168.1.0/24')
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
- # cidr = tree.find('192.168.1.0/24')
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(:CIDR => cidr)
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
- return(find_me(cidr))
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
- # subnets = tree.find_space(:IPCount => 16)
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
- return(list)
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
- # longest_match = tree.longest_match('192.168.1.1')
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
- # did_prune = tree.prune!('192.168.1.0/24')
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(:CIDR => cidr)
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
- # did_remove = tree.remove!('192.168.1.0/24')
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(:CIDR => cidr)
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
- # resized = tree.resize!('192.168.1.0/24', 23)
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(:CIDR => cidr)
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
- # puts tree.root('192.168.1.32/27')
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 nicely formatted string.
648
+ # Print the tree as a formatted string.
613
649
  #
614
- # puts tree.show()
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
- # puts tree.siblings('192.168.1.0/27')
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
- # supernets = tree.supernets()
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
- parent.tag[:Subnets].length.times do |index|
774
- index -= 1
775
- old_cidr = parent.tag[:Subnets][index]
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
- parent.tag[:Subnets][index] = nil
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].compact!
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
- if (parent)
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=nil)
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 netmask of cidr is greater by 1 bit position, then this is the parent.
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)
@@ -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,packed=false)
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 (!packed)
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, "Packed netmask, #{netmask}, is out of bounds for IPv#{version}."
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
- packed_netmask = 0
161
+ netmask_int = 0
162
162
 
163
163
  # validate & pack extended mask
164
164
  begin
165
- packed_netmask = pack_ip_addr(netmask, :Version => 4)
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 packed_mask. when we hit the firt '1' within
172
- # packed_mask (our netmask boundary), xor hostmask and
173
- # packed_mask. the result should be all 1's. this whole
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 = packed_netmask & hostmask
178
+ check = netmask_int & hostmask
179
179
  if ( check != 0)
180
180
  hostmask = hostmask >> 1
181
- unless ( (packed_netmask ^ hostmask) == all_f)
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