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/lib/cidr.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 CIDR
9
3
 
@@ -26,6 +20,9 @@ class CIDR
26
20
 
27
21
  # Hash of custom tags. Should be in the format tag => value.
28
22
  attr_reader :tag
23
+
24
+ # Integer of either 32 or 128 bits in length, with all bits set to 1
25
+ attr_reader :all_f
29
26
 
30
27
  # Hash of custom tags. Should be in the format tag => value.
31
28
  #
@@ -50,7 +47,7 @@ class CIDR
50
47
  #==============================================================================#
51
48
 
52
49
  # - Arguments:
53
- # * Hash with the following fields:
50
+ # * CIDR address as a string, or a Hash with the following fields:
54
51
  # - :CIDR -- IP address in CIDR notation - String (optional)
55
52
  # - :Netmask -- IP Netmask - String or Integer (optional)
56
53
  # - :PackedIP -- Integer representation of an IP address (optional)
@@ -66,7 +63,8 @@ class CIDR
66
63
  # * Netmask within :CIDR takes precedence over :Netmask.
67
64
  # * Version will be auto-detected if not specified
68
65
  #
69
- # Example:
66
+ # Examples:
67
+ # cidr4 = IPAdmin::CIDR.new('192.168.1.1/24')
70
68
  # cidr4 = IPAdmin::CIDR.new(:CIDR => '192.168.1.1/24')
71
69
  # cidr4_2 = IPAdmin::CIDR.new(:PackedIP => 0x0a010001,
72
70
  # :PackedNetmask => 0xffffff00
@@ -76,47 +74,51 @@ class CIDR
76
74
  # cidr6_2 = IPAdmin::CIDR.new(:CIDR => '::ffff:192.168.1.1/96')
77
75
  #
78
76
  def initialize(options)
79
- if (!options.kind_of? Hash)
80
- raise ArgumentError, "Expected Hash, but #{options.class} provided."
77
+ @tag = {}
78
+ if (!options.kind_of?(Hash) && !options.kind_of?(String))
79
+ raise ArgumentError, "Expected Hash or String, but #{options.class} provided."
81
80
  end
82
81
 
83
-
84
- if (options.has_key?(:PackedIP))
85
- packed_ip = options[:PackedIP]
86
- raise ArgumentError, "Expected Integer, but #{packed_ip.class} " +
87
- "provided for option :PackedIP." if (!packed_ip.kind_of?(Integer))
88
- elsif (options.has_key?(:CIDR))
89
- cidr = options[:CIDR]
90
- raise ArgumentError, "Expected String, but #{cidr.class} " +
91
- "provided for option :CIDR." if (!cidr.kind_of?(String))
92
- else
93
- raise ArgumentError, "Missing argument: CIDR or PackedIP."
94
- end
95
-
82
+ if (options.kind_of? String)
83
+ cidr = options
84
+ end
96
85
 
97
- if (options.has_key?(:PackedNetmask))
98
- packed_netmask = options[:PackedNetmask]
99
- raise ArgumentError, "Expected Integer, but #{packed_netmask.class} " +
100
- "provided for option :PackedNetmask." if (!packed_netmask.kind_of?(Integer))
101
-
102
- elsif (options.has_key?(:Netmask))
103
- netmask = options[:Netmask]
104
- raise ArgumentError, "Expected String or Integer, but #{netmask.class} " +
105
- "provided for option :Netmask." if (!netmask.kind_of?(String) && !netmask.kind_of?(Integer))
106
- end
86
+ if (options.kind_of? Hash)
87
+ if (options.has_key?(:PackedIP))
88
+ packed_ip = options[:PackedIP]
89
+ raise ArgumentError, "Expected Integer, but #{packed_ip.class} " +
90
+ "provided for option :PackedIP." if (!packed_ip.kind_of?(Integer))
91
+ elsif (options.has_key?(:CIDR))
92
+ cidr = options[:CIDR]
93
+ raise ArgumentError, "Expected String, but #{cidr.class} " +
94
+ "provided for option :CIDR." if (!cidr.kind_of?(String))
95
+ else
96
+ raise ArgumentError, "Missing argument: CIDR or PackedIP."
97
+ end
107
98
 
99
+ if (options.has_key?(:PackedNetmask))
100
+ packed_netmask = options[:PackedNetmask]
101
+ raise ArgumentError, "Expected Integer, but #{packed_netmask.class} " +
102
+ "provided for option :PackedNetmask." if (!packed_netmask.kind_of?(Integer))
103
+
104
+ elsif (options.has_key?(:Netmask))
105
+ netmask = options[:Netmask]
106
+ raise ArgumentError, "Expected String or Integer, but #{netmask.class} " +
107
+ "provided for option :Netmask." if (!netmask.kind_of?(String) && !netmask.kind_of?(Integer))
108
+ end
108
109
 
109
- if (options.has_key?(:Version))
110
- @version = options[:Version]
111
- if (@version != 4 && @version != 6)
112
- raise ArgumentError, ":Version should be 4 or 6, but was '#{version}'."
110
+ if (options.has_key?(:Version))
111
+ @version = options[:Version]
112
+ if (@version != 4 && @version != 6)
113
+ raise ArgumentError, ":Version should be 4 or 6, but was '#{version}'."
114
+ end
113
115
  end
114
- end
115
116
 
116
- if (options.has_key?(:Tag))
117
- @tag = options[:Tag]
118
- if (!@tag.kind_of? Hash)
119
- raise ArgumentError, "Expected Hash, but #{@tag.class} provided for option :Tag."
117
+ if (options.has_key?(:Tag))
118
+ @tag = options[:Tag]
119
+ if (!@tag.kind_of? Hash)
120
+ raise ArgumentError, "Expected Hash, but #{@tag.class} provided for option :Tag."
121
+ end
120
122
  end
121
123
  end
122
124
 
@@ -156,8 +158,7 @@ class CIDR
156
158
  @netmask = 2**128-1 if (!netmask && !packed_netmask)
157
159
  end
158
160
 
159
- # validate & pack ip
160
- IPAdmin.validate_ip_addr(:IP => ip, :Version => @version)
161
+ # pack ip
161
162
  @ip = IPAdmin.pack_ip_addr(:IP => ip, :Version => @version)
162
163
 
163
164
  end
@@ -208,8 +209,8 @@ class CIDR
208
209
  # - Returns:
209
210
  # * String
210
211
  #
211
- # Example:
212
- # arpa = cidr4.arpa() --> '1.168.192.in-addr.arpa.'
212
+ # Examples:
213
+ # arpa = cidr4.arpa()
213
214
  #
214
215
  def arpa()
215
216
 
@@ -270,8 +271,8 @@ class CIDR
270
271
  # - Returns:
271
272
  # * Integer.
272
273
  #
273
- # Example:
274
- # puts cidr4.bits() --> 24
274
+ # Examples:
275
+ # puts cidr4.bits()
275
276
  #
276
277
  def bits()
277
278
  return(IPAdmin.unpack_ip_netmask(:Integer => @netmask))
@@ -287,33 +288,35 @@ class CIDR
287
288
  #==============================================================================#
288
289
 
289
290
  # Determines if this CIDR contains (is supernet of)
290
- # the provided CIDR object.
291
+ # the provided CIDR addresss or IPAdmin::CIDR object.
291
292
  #
292
293
  # - Arguments:
293
- # * CIDR object
294
+ # * CIDR addresss or IPAdmin::CIDR object
294
295
  #
295
296
  # - Returns:
296
297
  # * true or false
297
298
  #
298
- # Example:
299
- # cidr4_2 = IPAdmin::CIDR.new(:CIDR => '192.168.1.0/26')
300
- # contains? = cidr4.contains(cidr4_2) --> true
299
+ # Examples:
300
+ # contains? = cidr4.contains('192.168.1.32/27')
301
301
  #
302
- def contains?(object)
302
+ def contains?(cidr)
303
303
  is_contained = false
304
304
 
305
- if (object.kind_of?(IPAdmin::CIDR))
306
- network = object.packed_network
307
- netmask = object.packed_netmask
308
-
309
- else
310
- raise ArgumentError, "Expected IPAdmin::CIDR " +
311
- " object but #{object.class} provided."
305
+ if (!cidr.kind_of?(IPAdmin::CIDR))
306
+ begin
307
+ cidr = IPAdmin::CIDR.new(:CIDR => cidr)
308
+ rescue Exception => error
309
+ raise ArgumentError, "Provided argument raised the following " +
310
+ "errors: #{error}"
311
+ end
312
312
  end
313
+
314
+ network = cidr.packed_network
315
+ netmask = cidr.packed_netmask
313
316
 
314
317
 
315
- if (object.version != @version)
316
- raise ArgumentError, "Attempted to compare a version #{object.version} CIDR " +
318
+ if (cidr.version != @version)
319
+ raise ArgumentError, "Attempted to compare a version #{cidr.version} CIDR " +
317
320
  "with a version #{@version} CIDR."
318
321
  end
319
322
 
@@ -349,11 +352,11 @@ class CIDR
349
352
  # - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
350
353
  #
351
354
  # - Returns:
352
- # * String
355
+ # * CIDR address as a String
353
356
  #
354
- # Example:
355
- # puts cidr4.desc() --> 192.168.1.0/24
356
- # puts cidr4.desc(:IP => true) --> 192.168.1.1/24
357
+ # Examples:
358
+ # puts cidr4.desc()
359
+ # puts cidr4.desc(:IP => true)
357
360
  #
358
361
  def desc(options=nil)
359
362
  short = false
@@ -404,10 +407,10 @@ class CIDR
404
407
  # - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
405
408
  #
406
409
  # - Returns:
407
- # * Array of Strings or CIDR objects
410
+ # * Array of IP address Strings or IPAdmin::CIDR objects
408
411
  #
409
- # Example:
410
- # ip_list = cidr4.enumerate(:Bitstep => 2, :Limit => 2) --> ['192.168.1.0','192.168.1.1']
412
+ # Examples:
413
+ # ip_list = cidr4.enumerate(:Bitstep => 2, :Limit => 2)
411
414
  #
412
415
  def enumerate(options=nil)
413
416
  bitstep = 1
@@ -465,6 +468,127 @@ class CIDR
465
468
  #======================================#
466
469
 
467
470
 
471
+ #==============================================================================#
472
+ # fill_in()
473
+ #==============================================================================#
474
+
475
+ # Given a list of subnets of the current CIDR, return a new list with any
476
+ # holes (missing subnets) filled in.
477
+ #
478
+ # - Arguments:
479
+ # * Array of CIDR addresses or IPAdmin::CIDR objects,
480
+ # or a Hash with the following fields:
481
+ # - :List -- Array of CIDR addresses or IPAdmin::CIDR objects
482
+ # - :Objectify -- if true, return IPAdmin::CIDR objects (optional)
483
+ # - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
484
+ #
485
+ # - Returns:
486
+ # * Array of CIDR address Strings or IPAdmin::CIDR objects
487
+ #
488
+ # Examples:
489
+ # subnets = cidr4.fill_in(['192.168.1.0/27','192.168.1.64/26','192.168.1.128/25'])
490
+ # subnets = cidr4.fill_in(:List => ['192.168.1.0/27','192.168.1.64/26'], :Objectify => true)
491
+ #
492
+
493
+ def fill_in(options)
494
+ short = false
495
+ objectify = false
496
+
497
+ # validate options
498
+ if ( options.kind_of?(Hash) )
499
+ if (!options.has_key?(:List))
500
+ raise ArgumentError, "Missing argument: List."
501
+ end
502
+
503
+ if (options.has_key?(:Short) && options[:Short] == true)
504
+ short = true
505
+ end
506
+
507
+ if (options.has_key?(:Objectify) && options[:Objectify] == true)
508
+ objectify = true
509
+ end
510
+
511
+ # make sure :List is an array
512
+ if ( !options[:List].kind_of?(Array) )
513
+ raise ArgumentError, "Expected Array for option :List, " +
514
+ "but #{list.class} provided."
515
+ end
516
+ list = options[:List]
517
+
518
+ elsif ( options.kind_of?(Array) )
519
+ list = options
520
+ else
521
+ raise ArgumentError, "Array or Hash expected but #{options.class} provided."
522
+ end
523
+
524
+ # validate each cidr and store in cidr_list
525
+ cidr_list = []
526
+ list.each do |obj|
527
+ if (!obj.kind_of?(IPAdmin::CIDR))
528
+ begin
529
+ obj = IPAdmin::CIDR.new(:CIDR => obj)
530
+ rescue Exception => error
531
+ aise ArgumentError, "A provided CIDR raised the following " +
532
+ "errors: #{error}"
533
+ end
534
+ end
535
+
536
+ if (!obj.version == self.version)
537
+ raise "#{obj.desc(:Short => true)} is not a version #{self.version} address."
538
+ end
539
+
540
+ # make sure we contain the cidr
541
+ if ( self.contains?(obj) == false )
542
+ raise "#{obj.desc(:Short => true)} does not fit " +
543
+ "within the bounds of #{self.desc(:Short => true)}."
544
+ end
545
+ cidr_list.push(obj)
546
+ end
547
+
548
+ # sort our cidr's and see what is missing
549
+ complete_list = []
550
+ expected = self.packed_network
551
+ IPAdmin.sort(cidr_list).each do |cidr|
552
+ network = cidr.packed_network
553
+ bitstep = (@all_f + 1) - cidr.packed_netmask
554
+
555
+ if (network > expected)
556
+ num_ips_missing = network - expected
557
+ sub_list = make_subnets_from_base_and_ip_count(expected,num_ips_missing)
558
+ complete_list.concat(sub_list)
559
+ elsif (network < expected)
560
+ next
561
+ end
562
+ complete_list.push(IPAdmin::CIDR.new(:PackedIP => network,
563
+ :PackedNetmask => cidr.packed_netmask,
564
+ :Version => self.version))
565
+ expected = network + bitstep
566
+ end
567
+
568
+ # if expected is not the next subnet, then we're missing subnets
569
+ # at the end of the cidr
570
+ next_sub = self.next_subnet(:Objectify => true).packed_network
571
+ if (expected != next_sub)
572
+ num_ips_missing = next_sub - expected
573
+ sub_list = make_subnets_from_base_and_ip_count(expected,num_ips_missing)
574
+ complete_list.concat(sub_list)
575
+ end
576
+
577
+ # decide what to return
578
+ if (!objectify)
579
+ subnets = []
580
+ complete_list.each {|entry| subnets.push(entry.desc(:Short => short))}
581
+ return(subnets)
582
+ else
583
+ return(complete_list)
584
+ end
585
+ end
586
+
587
+ #======================================#
588
+ #
589
+ #======================================#
590
+
591
+
468
592
  #==============================================================================#
469
593
  # hostmask_ext()
470
594
  #==============================================================================#
@@ -477,8 +601,8 @@ class CIDR
477
601
  # - Returns:
478
602
  # * String
479
603
  #
480
- # Example:
481
- # puts cidr4.hostmask_ext() --> 0.0.0.255
604
+ # Examples:
605
+ # puts cidr4.hostmask_ext()
482
606
  #
483
607
  def hostmask_ext()
484
608
  if (@version == 4)
@@ -507,10 +631,10 @@ class CIDR
507
631
  # - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
508
632
  #
509
633
  # - Returns:
510
- # * String or CIDR object.
634
+ # * IP address String or IPAdmin::CIDR object.
511
635
  #
512
- # Example:
513
- # puts cidr4.ip() --> 192.168.1.1
636
+ # Examples:
637
+ # puts cidr4.ip()
514
638
  #
515
639
  def ip(options=nil)
516
640
  objectify = false
@@ -560,15 +684,15 @@ class CIDR
560
684
  # - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
561
685
  #
562
686
  # - Returns:
563
- # * String or CIDR object.
687
+ # * IP address String or IPAdmin::CIDR object.
564
688
  #
565
689
  # - Notes:
566
690
  # * The broadcast() method is aliased to this method, and thus works for
567
691
  # IPv6 despite the fact that the IPv6 protocol does not support IP
568
692
  # broadcasting.
569
693
  #
570
- # Example:
571
- # puts cidr4.last() --> 192.168.1.255
694
+ # Examples:
695
+ # puts cidr4.last()
572
696
  #
573
697
  def last(options=nil)
574
698
  objectify = false
@@ -620,14 +744,14 @@ class CIDR
620
744
  # - :Objectify -- if true, return EUI objects (optional)
621
745
  #
622
746
  # - Returns:
623
- # * EUI object
747
+ # * IPAdmin::EUI48 object
624
748
  #
625
749
  # - Note:
626
750
  # * MAC address is based on original IP address passed during initialization.
627
751
  #
628
- # Example:
752
+ # Examples:
629
753
  # mcast = IPAdmin::CIDR.new(:CIDR => '224.0.0.6')
630
- # puts mcast.multicast_mac.address --> 01-00-5e-00-00-06
754
+ # puts mcast.multicast_mac.address
631
755
  #
632
756
  def multicast_mac(options=nil)
633
757
  objectify = false
@@ -660,7 +784,7 @@ class CIDR
660
784
  end
661
785
  end
662
786
 
663
- eui = IPAdmin::EUI.new(:PackedEUI => mac)
787
+ eui = IPAdmin::EUI48.new(:PackedEUI => mac)
664
788
  eui = eui.address if (!objectify)
665
789
 
666
790
  return(eui)
@@ -683,8 +807,8 @@ class CIDR
683
807
  # - Returns:
684
808
  # * String
685
809
  #
686
- # Example:
687
- # puts cidr4.netmask() --> /24
810
+ # Examples:
811
+ # puts cidr4.netmask()
688
812
  #
689
813
  def netmask()
690
814
  bits = IPAdmin.unpack_ip_netmask(:Integer => @netmask)
@@ -708,8 +832,8 @@ class CIDR
708
832
  # - Returns:
709
833
  # * String
710
834
  #
711
- # Example:
712
- # puts cidr4.netmask_ext() --> 255.255.255.0
835
+ # Examples:
836
+ # puts cidr4.netmask_ext()
713
837
  #
714
838
  def netmask_ext()
715
839
  if (@version == 4)
@@ -739,10 +863,10 @@ class CIDR
739
863
  # - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
740
864
  #
741
865
  # - Returns:
742
- # * String or CIDR object.
866
+ # * CIDR address String or IPAdmin::CIDR object.
743
867
  #
744
- # Example:
745
- # puts cidr4.network() --> 192.168.1.0
868
+ # Examples:
869
+ # puts cidr4.network()
746
870
  #
747
871
  def network(options=nil)
748
872
  objectify = false
@@ -796,10 +920,10 @@ class CIDR
796
920
  # - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
797
921
  #
798
922
  # - Returns:
799
- # * String or CIDR object.
923
+ # * IP address String or IPAdmin::CIDR object.
800
924
  #
801
- # Example:
802
- # puts cidr4.next_ip() --> 192.168.2.0
925
+ # Examples:
926
+ # puts cidr4.next_ip()
803
927
  #
804
928
  def next_ip(options=nil)
805
929
  bitstep = 1
@@ -861,10 +985,10 @@ class CIDR
861
985
  # - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
862
986
  #
863
987
  # - Returns:
864
- # * String or CIDR object.
988
+ # * CIDR address String or IPAdmin::CIDR object.
865
989
  #
866
- # Example:
867
- # puts cidr4.next_subnet() --> 192.168.2.0/24
990
+ # Examples:
991
+ # puts cidr4.next_subnet()
868
992
  #
869
993
  def next_subnet(options=nil)
870
994
  bitstep = 1
@@ -921,39 +1045,42 @@ class CIDR
921
1045
  # Provide the nth IP within this object.
922
1046
  #
923
1047
  # - Arguments:
924
- # * Hash with the following fields:
1048
+ # * Integer or a Hash with the following fields:
925
1049
  # - :Index -- index number of the IP address to return - Integer
926
1050
  # - :Objectify -- if true, return IPAdmin::CIDR objects (optional)
927
1051
  # - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
928
1052
  #
929
1053
  # - Returns:
930
- # * String or CIDR object.
1054
+ # * IP address String or IPAdmin::CIDR object.
931
1055
  #
932
- # Example:
933
- # puts cidr4.nth(:Index => 1) --> 192.168.1.1
1056
+ # Examples:
1057
+ # puts cidr4.nth(1)
1058
+ # puts cidr4.nth(:Index => 1, :Objectify => true)
934
1059
  #
935
1060
  def nth(options)
936
1061
  objectify = false
937
1062
  short = false
938
1063
 
939
- if (!options.kind_of?(Hash))
940
- raise ArgumentError, "Expected Hash, but " +
941
- "#{options.class} provided."
942
- end
943
-
944
- if ( !options.has_key?(:Index) )
945
- raise ArgumentError, "Missing argument: Index."
946
- end
947
- index = options[:Index]
1064
+ if (options.kind_of?(Hash))
1065
+ if ( !options.has_key?(:Index) )
1066
+ raise ArgumentError, "Missing argument: Index."
1067
+ end
1068
+ index = options[:Index]
948
1069
 
949
- if( options.has_key?(:Short) && options[:Short] == true )
950
- short = true
951
- end
1070
+ if( options.has_key?(:Short) && options[:Short] == true )
1071
+ short = true
1072
+ end
952
1073
 
953
- if( options.has_key?(:Objectify) && options[:Objectify] == true )
954
- objectify = true
1074
+ if( options.has_key?(:Objectify) && options[:Objectify] == true )
1075
+ objectify = true
1076
+ end
1077
+ elsif (options.kind_of?(Integer))
1078
+ index = options
1079
+ else
1080
+ raise ArgumentError, "Integer or Hash expected, but " +
1081
+ "#{options.class} provided."
955
1082
  end
956
-
1083
+
957
1084
  my_ip = @network + index
958
1085
  if ( (@hostmask | my_ip) == (@hostmask | @network) )
959
1086
 
@@ -989,8 +1116,8 @@ class CIDR
989
1116
  # - Returns:
990
1117
  # * Integer
991
1118
  #
992
- # Example:
993
- # puts cidr4.packed_hostmask().to_s(16) --> 0xff
1119
+ # Examples:
1120
+ # puts cidr4.packed_hostmask().to_s(16)
994
1121
  #
995
1122
  def packed_hostmask()
996
1123
  return(@hostmask)
@@ -1013,8 +1140,8 @@ class CIDR
1013
1140
  # - Returns:
1014
1141
  # * Integer
1015
1142
  #
1016
- # Example:
1017
- # puts cidr4.packed_ip().to_s(16) --> 0xc0c80101
1143
+ # Examples:
1144
+ # puts cidr4.packed_ip().to_s(16)
1018
1145
  #
1019
1146
  def packed_ip()
1020
1147
  return(@ip)
@@ -1037,8 +1164,8 @@ class CIDR
1037
1164
  # - Returns:
1038
1165
  # * Integer
1039
1166
  #
1040
- # Example:
1041
- # puts cidr4.packed_netmask().to_s(16) --> 0xffffff00
1167
+ # Examples:
1168
+ # puts cidr4.packed_netmask().to_s(16)
1042
1169
  #
1043
1170
  def packed_netmask()
1044
1171
  return(@netmask)
@@ -1061,8 +1188,8 @@ class CIDR
1061
1188
  # - Returns:
1062
1189
  # * Integer
1063
1190
  #
1064
- # Example:
1065
- # packed = cidr4.packed_network().to_s(16) --> 0xc0c80100
1191
+ # Examples:
1192
+ # packed = cidr4.packed_network().to_s(16)
1066
1193
  #
1067
1194
  def packed_network()
1068
1195
  return(@network)
@@ -1081,37 +1208,53 @@ class CIDR
1081
1208
  # between them (inclusive).
1082
1209
  #
1083
1210
  # - Arguments:
1084
- # * Hash with the following fields:
1211
+ # * Array of (2) Integers, or a Hash with the following fields:
1085
1212
  # - :Bitstep -- enumerate in X sized steps - Integer (optional)
1086
1213
  # - :Indexes -- index numbers of the addresses to use as boundaries - Array of (2) Integers
1087
1214
  # - :Objectify -- if true, return IPAdmin::CIDR objects (optional)
1088
1215
  # - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
1089
1216
  #
1090
1217
  # - Returns:
1091
- # * Array Strings or CIDR objects
1218
+ # * Array IP address Strings or IPAdmin::CIDR objects
1092
1219
  #
1093
- # Example:
1094
- # list = cidr4.range(:Indexes => [0,1]) --> ['192.168.1.0','192.168.1.1']
1220
+ # Examples:
1221
+ # list = cidr4.range([0,1])
1222
+ # list = cidr4.range(:Indexes => [0,1], :Objectify => true)
1095
1223
  #
1096
1224
  def range(options)
1097
1225
  objectify = false
1098
1226
  short = false
1099
1227
  bitstep = 1
1100
1228
 
1101
- if (!options.kind_of?(Hash))
1102
- raise Argumenterror, "Expected Hash, but #{options.class} provided."
1103
- end
1229
+ if (options.kind_of?(Hash))
1230
+ if ( !options.has_key?(:Indexes) )
1231
+ raise ArgumentError, "Missing argument: Indexes."
1232
+ end
1233
+ indexes = options[:Indexes]
1234
+ raise "Array expected but #{indexes.class} provided for argument: Indexes" if (!indexes.kind_of?(Array))
1235
+
1236
+ if( options.has_key?(:Short) && options[:Short] == true )
1237
+ short = true
1238
+ end
1239
+
1240
+ if( options.has_key?(:Objectify) && options[:Objectify] == true )
1241
+ objectify = true
1242
+ end
1104
1243
 
1105
- if ( !options.has_key?(:Indexes) )
1106
- raise ArgumentError, "Missing argument: Indexes."
1244
+ if( options.has_key?(:Bitstep) )
1245
+ bitstep = options[:Bitstep]
1246
+ end
1247
+ elsif (options.kind_of?(Array))
1248
+ indexes = options
1249
+ else
1250
+ raise Argumenterror, "Array or Hash expected, but #{options.class} provided."
1107
1251
  end
1108
- indexes = options[:Indexes]
1109
- indexes.sort!
1110
1252
 
1111
- if( (!indexes.kind_of?(Array)) || (indexes.length != 2))
1112
- raise ArgumentError, "Argument :Index should be an array of (2) index numbers."
1253
+ # validate & sort indexes
1254
+ indexes.sort!
1255
+ if (indexes.length != 2)
1256
+ raise "(2) index numbers are required."
1113
1257
  end
1114
-
1115
1258
  if ( (indexes[0] < 0) || (indexes[0] > self.size) )
1116
1259
  raise ArgumentError, "Index #{indexes[0]} is out of bounds for this CIDR."
1117
1260
  end
@@ -1120,18 +1263,7 @@ class CIDR
1120
1263
  raise ArgumentError, "Index #{indexes[1]} is out of bounds for this CIDR."
1121
1264
  end
1122
1265
 
1123
- if( options.has_key?(:Short) && options[:Short] == true )
1124
- short = true
1125
- end
1126
-
1127
- if( options.has_key?(:Objectify) && options[:Objectify] == true )
1128
- objectify = true
1129
- end
1130
-
1131
- if( options.has_key?(:Bitstep) )
1132
- bitstep = options[:Bitstep]
1133
- end
1134
-
1266
+ # make range
1135
1267
  start_ip = @network + indexes[0]
1136
1268
  end_ip = @network + indexes[1]
1137
1269
  my_ip = start_ip
@@ -1160,51 +1292,59 @@ class CIDR
1160
1292
  # remainder()
1161
1293
  #==============================================================================#
1162
1294
 
1163
- # Given a portion of the current CIDR, provide the remainder of
1164
- # the CIDR. For example if the original CIDR is 192.168.0.0/24 and you
1295
+ # Given a single subnet of the current CIDR, provide the remainder of
1296
+ # the subnets. For example if the original CIDR is 192.168.0.0/24 and you
1165
1297
  # provide 192.168.0.64/26 as the portion to exclude, then 192.168.0.0/26,
1166
- # and 192.168.0.128/25 will be returned as the remainder.
1298
+ # and 192.168.0.128/25 will be returned as the remainders.
1167
1299
  #
1168
1300
  # - Arguments:
1169
- # * Optional hash with the following fields:
1170
- # - :Exclude -- CIDR object to use in calculating the remainder.
1301
+ # * CIDR address or IPAdmin::CIDR object, or a Hash with the following fields:
1302
+ # - :Exclude -- CIDR address or IPAdmin::CIDR object.
1171
1303
  # - :Objectify -- if true, return IPAdmin::CIDR objects (optional)
1172
1304
  # - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
1173
1305
  #
1174
1306
  # - Returns:
1175
- # * Array of Strings or CIDR objects
1307
+ # * Array of CIDR address Strings or IPAdmin::CIDR objects
1176
1308
  #
1177
1309
  #
1178
- # Example:
1179
- # cidr4_2 = IPAdmin::CIDR.new(:CIDR => '192.168.1.64/26')
1180
- # cidr4.remainder(:Exclude => cidr4_2).each {|x| puts}
1310
+ # Examples:
1311
+ # cidr4.remainder('192.168.1.32/27').each {|x| puts x}
1312
+ # cidr4.remainder(:Exclude => '192.168.1.32/27', :Objectify => true).each {|x| puts x.desc}
1181
1313
  #
1182
1314
  def remainder(options)
1183
1315
  short = nil
1184
1316
  objectify = nil
1185
1317
 
1186
- if (!options.kind_of? Hash)
1187
- raise ArgumentError, "Expected Hash, but #{options.class} provided."
1188
- end
1189
-
1190
- if ( !options.has_key?(:Exclude) )
1191
- raise ArgumentError, "Missing argument: Exclude."
1192
- end
1193
- to_exclude = options[:Exclude]
1318
+ if (options.kind_of? Hash)
1319
+ if ( !options.has_key?(:Exclude) )
1320
+ raise ArgumentError, "Missing argument: Exclude."
1321
+ end
1322
+ to_exclude = options[:Exclude]
1194
1323
 
1195
- if ( !to_exclude.kind_of?(IPAdmin::CIDR) )
1196
- raise ArgumentError, "Expeced IPAdmin::CIDR, but #{exclude.class} " +
1197
- "for option: Exclude."
1198
- end
1324
+ if( options.has_key?(:Short) && options[:Short] == true )
1325
+ short = true
1326
+ end
1199
1327
 
1200
- if( options.has_key?(:Short) && options[:Short] == true )
1201
- short = true
1328
+ if( options.has_key?(:Objectify) && options[:Objectify] == true )
1329
+ objectify = true
1330
+ end
1331
+
1332
+ elsif
1333
+ to_exclude = options
1334
+ else
1335
+ raise ArgumentError, "CIDR address or Hash expected, but #{options.class} provided."
1202
1336
  end
1203
1337
 
1204
- if( options.has_key?(:Objectify) && options[:Objectify] == true )
1205
- objectify = true
1338
+ if ( !to_exclude.kind_of?(IPAdmin::CIDR) )
1339
+ begin
1340
+ to_exclude = IPAdmin::CIDR.new(:CIDR => to_exclude)
1341
+ rescue Exception => error
1342
+ raise ArgumentError, "Argument :Exclude raised the following " +
1343
+ "errors: #{error}"
1344
+ end
1206
1345
  end
1207
1346
 
1347
+
1208
1348
  # make sure 'to_exclude' is the same ip version
1209
1349
  if ( to_exclude.version != @version )
1210
1350
  raise "#{to_exclude.desc(:Short => true)} is of a different " +
@@ -1266,26 +1406,29 @@ class CIDR
1266
1406
  # Return the resulting CIDR as a new object.
1267
1407
  #
1268
1408
  # - Arguments:
1269
- # * Hash with the following fields:
1270
- # - :Subnet -- Number of bits of new Netmask - Integer
1409
+ # * Integer, or a Hash with the following fields:
1410
+ # - :Netmask -- Number of bits of new Netmask - Integer
1271
1411
  #
1272
1412
  # - Returns:
1273
- # * CIDR object
1413
+ # * IPAdmin::CIDR object
1274
1414
  #
1275
- # Example:
1276
- # new_cidr = cidr4.resize(:Subnet => 23)
1277
- # puts new_cidr.desc --> 192.168.1.0/23
1415
+ # Examples:
1416
+ # new_cidr = cidr4.resize(23)
1417
+ # new_cidr = cidr4.resize(:Netmask => 23)
1418
+ # puts new_cidr.desc
1278
1419
  #
1279
1420
  def resize(options)
1280
- if (!options.kind_of?(Hash))
1281
- raise Argumenterror, "Expected Hash, but " +
1421
+ if (options.kind_of?(Hash))
1422
+ if ( !options.has_key?(:Netmask) )
1423
+ raise Argumenterror, "Missing argument: Netmask."
1424
+ end
1425
+ bits = options[:Netmask]
1426
+ elsif (options.kind_of?(Integer))
1427
+ bits = options
1428
+ else
1429
+ raise Argumenterror, "Integer or Hash expected, but " +
1282
1430
  "#{options.class} provided."
1283
1431
  end
1284
-
1285
- if ( !options.has_key?(:Subnet) )
1286
- raise Argumenterror, "Missing argument: Subnet."
1287
- end
1288
- bits = options[:Subnet]
1289
1432
 
1290
1433
  IPAdmin.validate_ip_netmask(:Netmask => bits, :Version => @version)
1291
1434
  netmask = IPAdmin.pack_ip_netmask(:Netmask => bits, :Version => @version)
@@ -1307,30 +1450,32 @@ class CIDR
1307
1450
  # Resize this object by changing the size of the Netmask.
1308
1451
  #
1309
1452
  # - Arguments:
1310
- # * Hash with the following fields:
1311
- # - :Subnet -- Number of bits of new Netmask - Integer
1453
+ # * Integer, or a Hash with the following fields:
1454
+ # - :Netmask -- Number of bits of new Netmask - Integer
1312
1455
  #
1313
1456
  # - Returns:
1314
- # * nil
1457
+ # * True
1315
1458
  #
1316
1459
  # - Notes:
1317
1460
  # * If CIDR is resized such that the original IP is no longer contained within,
1318
1461
  # then that IP will be reset to the base network address.
1319
1462
  #
1320
- # Example:
1321
- # cidr4.resize!(:Subnet => 23)
1322
- # puts cidr4.desc --> 192.168.1.0/23
1463
+ # Examples:
1464
+ # cidr4.resize!(23)
1465
+ # puts cidr4.desc
1323
1466
  #
1324
1467
  def resize!(options)
1325
- if (!options.kind_of?(Hash))
1326
- raise Argumenterror, "Expected Hash, but " +
1468
+ if (options.kind_of?(Hash))
1469
+ if ( !options.has_key?(:Netmask) )
1470
+ raise Argumenterror, "Missing argument: Netmask."
1471
+ end
1472
+ bits = options[:Netmask]
1473
+ elsif (options.kind_of?(Integer))
1474
+ bits = options
1475
+ else
1476
+ raise Argumenterror, "Integer or Hash expected, but " +
1327
1477
  "#{options.class} provided."
1328
1478
  end
1329
-
1330
- if ( !options.has_key?(:Subnet) )
1331
- raise Argumenterror, "Missing argument: Subnet."
1332
- end
1333
- bits = options[:Subnet]
1334
1479
 
1335
1480
  IPAdmin.validate_ip_netmask(:Netmask => bits, :Version => @version)
1336
1481
  netmask = IPAdmin.pack_ip_netmask(:Netmask => bits, :Version => @version)
@@ -1344,7 +1489,7 @@ class CIDR
1344
1489
  @ip = @network
1345
1490
  end
1346
1491
 
1347
- return(nil)
1492
+ return(true)
1348
1493
  end
1349
1494
 
1350
1495
  #======================================#
@@ -1364,8 +1509,8 @@ class CIDR
1364
1509
  # - Returns:
1365
1510
  # * Integer
1366
1511
  #
1367
- # Example:
1368
- # puts cidr4.size() --> 256
1512
+ # Examples:
1513
+ # puts cidr4.size()
1369
1514
  #
1370
1515
  def size()
1371
1516
  return(@hostmask + 1)
@@ -1380,11 +1525,14 @@ class CIDR
1380
1525
  # subnet()
1381
1526
  #==============================================================================#
1382
1527
 
1383
- # Subnet this object. Object will be fully subnetted into X number of subnets
1384
- # of specified size. If :MinCount is provided, then method will return at least
1385
- # that number of subnets (of size X) and the remainder of the new subnets
1386
- # will be merged together as tightly as possible. If a size is not provided,
1387
- # then the current CIDR will be split in half.
1528
+ # Subnet this object. There are 2 ways to subnet:
1529
+ # * By providing the netmask of the new subnets in :Subnet.
1530
+ # * By providing the number of IP addresses needed in the new subnets in :IPCount
1531
+ #
1532
+ # If :Mincount is not provided, then the CIDR will be fully subnetted. Otherwise,
1533
+ # if provided then :Mincount number of subnets of requested size will be returned and
1534
+ # the remainder of the subnets will be summarized as much as possible. If neither :Subnet
1535
+ # or :IPCount is provided, then the current CIDR will be split in half.
1388
1536
  #
1389
1537
  # - Arguments:
1390
1538
  # * Optional hash with the following fields:
@@ -1395,15 +1543,14 @@ class CIDR
1395
1543
  # - :Subnet -- Netmask (in bits) of new subnets - Integer (optional)
1396
1544
  #
1397
1545
  # - Returns:
1398
- # * Array of CIDR addresses or IPAdmin::CIDR objects
1546
+ # * Array of CIDR address Strings or IPAdmin::CIDR objects
1399
1547
  #
1400
1548
  # - Notes:
1401
1549
  # * :Subnet always takes precedence over :IPCount.
1402
1550
  #
1403
- # Example:
1551
+ # Examples:
1404
1552
  # cidr_list = cidr4.subnet(:Subnet => 28, :MinCount => 3)
1405
1553
  # cidr_list = cidr4.subnet(:IPCount => 19)
1406
- # puts cidr_list[0] --> 192.168.1.0/27
1407
1554
  #
1408
1555
  def subnet(options=nil)
1409
1556
  my_network = self.packed_network
@@ -1516,6 +1663,61 @@ class CIDR
1516
1663
  #
1517
1664
  #======================================#
1518
1665
 
1666
+
1667
+ # PRIVATE INSTANCE METHODS
1668
+ private
1669
+
1670
+
1671
+ #==============================================================================#
1672
+ # make_subnets_from_base_and_ip_count()
1673
+ #==============================================================================#
1674
+
1675
+ # Make CIDR addresses from a base addr and an number of ip's to encapsulate.
1676
+ #
1677
+ # - Arguments:
1678
+ # * base ip as packed integer
1679
+ # * number of ip's required
1680
+ #
1681
+ # - Returns:
1682
+ # * array of IPAdmin::CIDR objects
1683
+ #
1684
+ def make_subnets_from_base_and_ip_count(base_addr,ip_count)
1685
+ list = []
1686
+ until (ip_count == 0)
1687
+ mask = @all_f
1688
+ multiplier = 0
1689
+ bitstep = 0
1690
+ last_addr = base_addr
1691
+ done = false
1692
+ until (done == true)
1693
+ if (bitstep < ip_count && (base_addr & mask == last_addr & mask) )
1694
+ multiplier += 1
1695
+ elsif (bitstep > ip_count || (base_addr & mask != last_addr & mask) )
1696
+ multiplier -= 1
1697
+ done = true
1698
+ else
1699
+ done = true
1700
+ end
1701
+ bitstep = 2**multiplier
1702
+ mask = @all_f << multiplier & @all_f
1703
+ last_addr = base_addr + bitstep - 1
1704
+ end
1705
+
1706
+ list.push(IPAdmin::CIDR.new(:PackedIP => base_addr,
1707
+ :PackedNetmask => mask,
1708
+ :Version => self.version))
1709
+ ip_count -= bitstep
1710
+ base_addr += bitstep
1711
+ end
1712
+
1713
+ return(list)
1714
+ end
1715
+
1716
+ #======================================#
1717
+ #
1718
+ #======================================#
1719
+
1720
+
1519
1721
  end
1520
1722
 
1521
1723
  end # module IPAdmin