ipadmin 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/methods.rb CHANGED
@@ -1,68 +1,63 @@
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
-
8
1
  module IPAdmin
9
2
 
10
3
  #==============================================================================#
11
4
  # compare()
12
5
  #==============================================================================#
13
6
 
14
- # Compare CIDR or NetStruct objects, and determine if one
7
+ # Compare (2) CIDR addresses, and determine if one
15
8
  # is the supernet of the other.
16
9
  #
17
10
  # - Arguments:
18
- # * Two CIDR or NetStruct objects
11
+ # * (2) CIDR addresses or IPAdmin::CIDR objects
19
12
  #
20
13
  # - Returns:
21
- # * if one object is a subnet of another, then return an array in order of
22
- # [supernet,subnet]
14
+ # * if one is a subnet of another, then return original array in order of [supernet,subnet]
23
15
  # * if both are equal, return 1
24
16
  # * if neither is a supernet of the other, return nil
25
17
  #
26
- # Example:
18
+ # Examples:
27
19
  # supernet,subnet = IPAdmin.compare(cidr1,cidr2)
20
+ # supernet,subnet = IPAdmin.compare('192.168.1.0/24','192.168.1.32/27')
28
21
  #
29
22
 
30
- def compare(obj1,obj2)
23
+ def compare(cidr1,cidr2)
31
24
  ret_val = nil
32
-
33
- # validate arguments
34
- if ( !obj1.kind_of?(IPAdmin::CIDR) &&
35
- !obj1.kind_of?(IPAdmin::NetStruct) )
36
- raise ArgumentError, "Expected IPAdmin::CIDR or NetStruct " +
37
- "as first argument, but #{obj1.class} provided."
25
+ orig1 = cidr1
26
+ orig2 = cidr2
27
+
28
+ # if args are not CIDR objects, then attempt to create
29
+ # cidr objects from them
30
+ if ( !cidr1.kind_of?(IPAdmin::CIDR) )
31
+ begin
32
+ cidr1 = IPAdmin::CIDR.new(:CIDR => cidr1)
33
+ rescue Exception => error
34
+ raise ArgumentError, "First provided argument raised the following " +
35
+ "errors: #{error}"
36
+ end
38
37
  end
39
38
 
40
- if ( !obj2.kind_of?(IPAdmin::CIDR) &&
41
- !obj2.kind_of?(IPAdmin::NetStruct) )
42
- raise ArgumentError, "Expected IPAdmin::CIDR or NetStruct " +
43
- "as second argument, but #{obj2.class} provided."
39
+ if ( !cidr2.kind_of?(IPAdmin::CIDR))
40
+ begin
41
+ cidr2 = IPAdmin::CIDR.new(:CIDR => cidr2)
42
+ rescue Exception => error
43
+ raise ArgumentError, "Second provided argument raised the following " +
44
+ "errors: #{error}"
45
+ end
44
46
  end
45
47
 
46
48
  # make sure both are same version
47
- if (obj1.version != obj2.version )
48
- raise ArgumentError, "Provided objects are of different IP versions."
49
+ if (cidr1.version != cidr2.version )
50
+ raise ArgumentError, "Provided CIDR addresses are of different IP versions."
49
51
  end
50
52
 
51
53
 
52
54
  # get network/netmask of each
53
- objects = [obj1,obj2]
55
+ objects = [cidr1,cidr2]
54
56
  networks = []
55
57
  netmasks = []
56
58
  for obj in objects
57
- if ( obj.kind_of?(IPAdmin::CIDR) )
58
- networks.push(obj.packed_network)
59
- netmasks.push(obj.packed_netmask)
60
-
61
- elsif ( obj.kind_of?(IPAdmin::NetStruct) )
62
- networks.push(obj.network)
63
- netmasks.push(obj.netmask)
64
-
65
- end
59
+ networks.push(obj.packed_network)
60
+ netmasks.push(obj.packed_netmask)
66
61
  end
67
62
 
68
63
  # return 1's if objects are equal otherwise
@@ -73,11 +68,11 @@ def compare(obj1,obj2)
73
68
  ret_val = 1
74
69
  elsif (netmasks[0] < netmasks[1])
75
70
  if ( (netmasks[0] & networks[0]) == (netmasks[0] & networks[1]) )
76
- ret_val = [obj1,obj2]
71
+ ret_val = [orig1,orig2]
77
72
  end
78
73
  elsif (netmasks[1] < netmasks[0])
79
74
  if ( (netmasks[1] & networks[0]) == (netmasks[1] & networks[1]) )
80
- ret_val = [obj2,obj1]
75
+ ret_val = [orig2,orig1]
81
76
  end
82
77
  end
83
78
 
@@ -90,69 +85,26 @@ module_function :compare
90
85
  #======================================#
91
86
 
92
87
 
93
- #==============================================================================#
94
- # create_net_struct()
95
- #==============================================================================#
96
-
97
- # Create a NetStruct object from an CIDR or NetStruct object.
98
- # This type of Struct is used internally for various tasks, and is not likely
99
- # to be useful to anyone.
100
- #
101
- # - Arguments:
102
- # * CIDR or NetStruct object
103
- #
104
- # - Returns:
105
- # * NetStruct object
106
- #
107
- # Example:
108
- # net_struct = IPAdmin.create_net_struct(object)
109
- #
110
- def create_net_struct(object)
111
-
112
- if ( object.kind_of?(IPAdmin::CIDR) )
113
- network = object.packed_ip
114
- netmask = object.packed_netmask
115
-
116
- elsif ( object.kind_of?(IPAdmin::NetStruct) )
117
- network = object.network
118
- netmask = object.netmask
119
- else
120
- raise ArgumentError, "Expected IPAdmin::CIDR or NetStruct "+
121
- "object, but #{object.class} provided."
122
- end
123
-
124
- version = object.version
125
- net_struct = NetStruct.new(network,netmask,version,object,[])
126
-
127
- return(net_struct)
128
- end
129
- module_function :create_net_struct
130
-
131
- #======================================#
132
- #
133
- #======================================#
134
-
135
-
136
88
  #==============================================================================#
137
89
  # merge()
138
90
  #==============================================================================#
139
91
 
140
- # Given a list of CIDR or NetStruct objects
141
- # merge (supernet) them in the most efficient way possible. Supernetting
142
- # will only occur when the newly created supernet will not result in the
92
+ # Given a list of CIDR addresses or IPAdmin::CIDR objects of the same version,
93
+ # merge (summarize) them in the most efficient way possible. Summarization
94
+ # will only occur when the newly created supernets will not result in the
143
95
  # 'creation' of additional space. For example the following blocks
144
- # (192.168.0.0/24, 192.168.1.0/24, and 192.168.2.0/24) would merge into
96
+ # (192.168.0.0/24, 192.168.1.0/24, and 192.168.2.0/24) would be summarized into
145
97
  # 192.168.0.0/23 and 192.168.2.0/24 rather than into 192.168.0.0/22
146
98
  #
147
99
  # - Arguments:
148
- # * Hash with the following fields:
149
- # - :List -- Array of CIDR or NetStruct objects
150
- # - :NetStruct -- if true, return IPAdmin::NetStruct objects (optional)
100
+ # * Array of CIDR addresses or IPAdmin::CIDR objects, or a Hash with
101
+ # the following fields:
102
+ # - :List -- Array of CIDR addresses or IPAdmin::CIDR objects
151
103
  # - :Objectify -- if true, return IPAdmin::CIDR objects (optional)
152
104
  # - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
153
105
  #
154
106
  # - Returns:
155
- # * Array of CIDR or NetStruct objects
107
+ # * Array of CIDR address Strings or IPAdmin::CIDR objects
156
108
  #
157
109
  # - Notes:
158
110
  # * I have designed this with enough flexibility that you can pass in CIDR
@@ -160,211 +112,155 @@ module_function :create_net_struct
160
112
  # 10.1.0.0/26, 10.1.0.64/26) and they will be merged properly (ie 192.168.1.0/25,
161
113
  # and 10.1.0.0/25 would be returned).
162
114
  #
163
- # Example:
164
- # supernets = IPAdmin.merge(:List => list)
115
+ # Examples:
116
+ # supernets = IPAdmin.merge(['192.168.1.0/27','192.168.1.32/27'])
117
+ # supernets = IPAdmin.merge(:List => ['192.168.1.0/27','192.168.1.32/27'], :Short => true)
165
118
  #
166
119
  def merge(options)
167
120
  version = nil
121
+ all_f = nil
168
122
  short = false
169
123
  objectify = false
170
124
 
171
125
  # validate options
172
- if ( !options.kind_of?(Hash) )
173
- raise ArgumentError, "Hash expected but #{options.class} provided."
174
- end
175
-
176
- if (!options.has_key?(:List))
177
- raise ArgumentError, "Missing argument: List."
178
- end
126
+ if ( options.kind_of?(Hash) )
127
+ if (!options.has_key?(:List))
128
+ raise ArgumentError, "Missing argument: List."
129
+ end
179
130
 
180
- if (options.has_key?(:Short) && options[:Short] == true)
181
- short = true
182
- end
131
+ if (options.has_key?(:Short) && options[:Short] == true)
132
+ short = true
133
+ end
183
134
 
184
- if (options.has_key?(:Objectify) && options[:Objectify] == true)
185
- objectify = true
186
- end
187
-
188
- list = options[:List]
189
- ret_struct = 1 if (options.has_key?(:NetStruct))
135
+ if (options.has_key?(:Objectify) && options[:Objectify] == true)
136
+ objectify = true
137
+ end
190
138
 
191
- # make sure list is an array
192
- if ( !list.kind_of?(Array) )
193
- raise ArgumentError, "Expected Array for option :List, " +
194
- "but #{list.class} provided."
139
+ # make sure :List is an array
140
+ if ( !options[:List].kind_of?(Array) )
141
+ raise ArgumentError, "Expected Array for option :List, " +
142
+ "but #{list.class} provided."
143
+ end
144
+ list = options[:List]
145
+
146
+ elsif ( options.kind_of?(Array) )
147
+ list = options
148
+
149
+ else
150
+ raise ArgumentError, "Array or Hash expected but #{options.class} provided."
195
151
  end
196
-
152
+
197
153
  # make sure all are valid types of the same IP version
154
+ supernet_list = []
198
155
  list.each do |obj|
199
- if (!obj.kind_of?(IPAdmin::CIDR) && !obj.kind_of?(IPAdmin::NetStruct) )
200
- raise ArgumentError, "Expected IPAdmin::CIDR or NetStruct " +
201
- "object but #{obj.class} provided."
156
+ if (!obj.kind_of?(IPAdmin::CIDR))
157
+ begin
158
+ obj = IPAdmin::CIDR.new(:CIDR => obj)
159
+ rescue Exception => error
160
+ raise ArgumentError, "An array element of :List raised the following " +
161
+ "errors: #{error}"
162
+ end
202
163
  end
203
164
 
204
165
  version = obj.version if (!version)
166
+ all_f = obj.all_f if (!all_f)
205
167
  if (!obj.version == version)
206
168
  raise "Provided objects must be of the same IP version."
207
169
  end
170
+ supernet_list.push(obj)
208
171
  end
209
172
 
210
- # make all_f
211
- if (version == 4)
212
- all_f = 2**32 - 1
213
- else
214
- all_f = 2**128 - 1
215
- end
216
-
217
- # make sure that our list is in order, and contains no duplicates
218
- list = IPAdmin.sort(list)
219
- index = 0
220
- (list.length).times do
221
- if ((index > 0)&&(IPAdmin.compare(list[index],list[index-1]) == 1))
222
- list.delete_at(index)
223
- else
224
- index += 1
225
- end
226
- end
227
-
228
- # create supernet_list from list
229
- supernet_list = []
230
- list.each do |obj|
231
- if (obj.kind_of?(IPAdmin::CIDR))
232
- supernet_list.push(IPAdmin.create_net_struct(obj))
233
-
234
- elsif ( obj.kind_of?(IPAdmin::NetStruct) )
235
- if (obj.subnets && obj.subnets.length > 0)
236
- # get all child subnets of this branch entry
237
- children = merge(:List => obj.subnets, :NetStruct => 1)
238
-
239
- # if any child subnets are equal to the parent subnet
240
- # then copy the grandchild subnets and delete the child
241
- children.each do |child|
242
- if ( (obj.network == child.network) &&
243
- (obj.netmask == child.netmask) )
244
- if (child.subnets && child.subnets.length > 0)
245
- grandchildren = child.subnets
246
- children.concat(grandchildren)
247
- end
248
- children.delete(child)
249
- children = IPAdmin.sort(children)
250
- break
251
- end
252
- end
253
-
254
- obj.subnets.clear
255
- obj.subnets.concat(children)
256
- end
257
-
258
- supernet_list.push(obj)
259
- end
260
- end
261
-
262
- # merge subnets of this new branch by removing them from 'supernet_list',
263
- # and categorizing them into hash of arrays (key=netmask)
173
+ # merge subnets by removing them from 'supernet_list',
174
+ # and categorizing them into hash of arrays ({packed_netmask => [packed_network,packed_network,etc...] )
264
175
  # within each categorization we merge contiguous subnets
265
176
  # and then remove them from that category & put them back into
266
- # 'supernet_list'. we do this until our list stops getting any shorter
177
+ # 'supernet_list'. we do this until supernet_list stops getting any shorter
267
178
  categories = {}
268
179
  supernet_list_length = 0
269
180
  until (supernet_list_length == supernet_list.length)
270
181
  supernet_list_length = supernet_list.length
271
182
 
272
183
  # categorize
273
- supernet_list.each do |entry|
274
- netmask = entry.netmask
184
+ supernet_list.each do |cidr|
185
+ netmask = cidr.packed_netmask
186
+ network = cidr.packed_network
275
187
  if (categories.has_key?(netmask) )
276
- (categories[netmask]).push(entry)
188
+ categories[netmask].push(network)
277
189
  else
278
- categories[netmask] = [entry]
190
+ categories[netmask] = [network]
279
191
  end
280
192
  end
281
193
  supernet_list.clear
282
194
 
283
- categories.each_key do |netmask|
284
- entries = categories[netmask]
195
+ ordered_cats = categories.keys.sort
196
+ ordered_cats.each do |netmask|
197
+ nets = categories[netmask].sort
285
198
  bitstep = (all_f + 1) - netmask
286
-
287
- # this entire process depends on the list being in order
288
- until (entries.length == 0)
199
+
200
+ until (nets.length == 0)
201
+ # take the first network & create its supernet. this
202
+ # supernet will have x number of subnets, so we'll look
203
+ # & see if we have those subnets. if so, keep supernet & delete subnets.
289
204
  to_merge = []
290
205
  multiplier = 1
291
- first = entries[0]
206
+ network1 = nets[0]
292
207
  num_required = 2**multiplier
293
208
  supermask = (netmask << multiplier) & all_f
294
- supernet = supermask & first.network
295
- if (first.network == supernet)
296
- # take first entry and use it to form a base
297
- # supernet address. this supernet should have
298
- # x number of subnets in it, so we look for
299
- # those subnets & if found store them
300
- expected = first.network
301
- entries.each do |entry|
302
- if ( (entry.network == expected) && (first.network == supernet) )
303
- to_merge.push(entry)
209
+ supernet = supermask & network1
210
+ if (network1 == supernet)
211
+ # we have the first half of the new supernet
212
+ expected = network1
213
+ nets.each do |network|
214
+ if (network == expected)
215
+ to_merge.push(network)
304
216
  expected = expected + bitstep
305
- if ( (to_merge.length == num_required) &&
306
- (entries.length > num_required ) )
217
+ if ( (to_merge.length == num_required) && (nets.length > num_required) )
218
+ # we have all of our subnets for this round, but still have
219
+ # more to look at
307
220
  multiplier += 1
308
221
  num_required = 2**multiplier
309
222
  supermask = (netmask << multiplier) & all_f
310
- supernet = supermask & first.network
223
+ supernet = supermask & network1
311
224
  end
312
225
  else
313
- # if entry is a duplicate, then kill it
314
- if (IPAdmin.compare(entry,to_merge.last) == 1)
315
- entries.delete(entry)
316
- end
317
226
  break
318
227
  end
319
228
  end
320
229
  else
321
- to_merge.push(first)
230
+ # we have the second half of the new supernet only
231
+ to_merge.push(network1)
322
232
  end
323
233
 
324
- # make sure we actually have all of our subnets
325
- # create our new supernet
234
+
326
235
  if (to_merge.length != num_required)
236
+ # we dont have all of our subnets, so backstep 1 bit
327
237
  multiplier -= 1
328
238
  supermask = (netmask << multiplier) & all_f
329
- supernet = supermask & first.network
239
+ supernet = supermask & network1
330
240
  end
331
- net_struct = NetStruct.new(supernet,supermask,version,nil,[])
332
-
333
- # now that we have the child members of our new supernet
334
- # take any grandchild subnets that they may have and
335
- # add them to the new supernet. then kill the children
336
- (2**multiplier).times do
337
- to_kill = to_merge.shift
338
- net_struct.subnets.concat(to_kill.subnets) if (to_kill.subnets)
339
- entries.delete(to_kill)
340
- end
341
- supernet_list.push(net_struct)
241
+
242
+ # save new supernet
243
+ supernet_list.push(IPAdmin::CIDR.new(:PackedIP => supernet,
244
+ :PackedNetmask => supermask,
245
+ :Version => version))
246
+
247
+ # delete the subnets of the new supernet
248
+ (2**multiplier).times {nets.delete(to_merge.shift)}
342
249
  end
343
250
  end
344
251
  categories.clear
345
252
  supernet_list = IPAdmin.sort(supernet_list)
346
253
  end
347
254
 
348
- # if '!ret_struct', return CIDR's
349
- if (!ret_struct)
350
- supernets = []
351
- supernet_list.each do |entry|
352
- if (!objectify)
353
- network = IPAdmin.unpack_ip_addr(:Integer => entry.network, :Version => version)
354
- network = IPAdmin.shorten(network) if (short && version == 6)
355
- netmask = IPAdmin.unpack_ip_netmask(:Integer => entry.netmask, :Version => version)
356
- supernets.push("#{network}/#{netmask}")
357
- else
358
- supernets.push(IPAdmin::CIDR.new(:PackedIP => entry.network,
359
- :PackedNetmask => entry.netmask,
360
- :Version => version))
361
- end
362
- end
255
+ # decide what to return
256
+ if (!objectify)
257
+ supernets = []
258
+ supernet_list.each {|entry| supernets.push(entry.desc(:Short => short))}
259
+ return(supernets)
363
260
  else
364
- supernets = supernet_list
261
+ return(supernet_list)
365
262
  end
366
263
 
367
- return(supernets)
368
264
  end
369
265
  module_function :merge
370
266
 
@@ -378,10 +274,10 @@ module_function :merge
378
274
  #==============================================================================#
379
275
 
380
276
  # Given the number of IP addresses required in a subnet, return the minimum
381
- # netmask required for that subnet.
277
+ # netmask (in bits) required for that subnet.
382
278
  #
383
279
  # - Arguments:
384
- # * Hash with the following fields:
280
+ # * Integer or Hash with the following fields:
385
281
  # - :IPCount -- the number of IP addresses required - Integer
386
282
  # - :Version -- IP version - Integer(optional)
387
283
  #
@@ -391,23 +287,26 @@ module_function :merge
391
287
  # - Notes:
392
288
  # * Version is assumed to be 4 unless specified otherwise.
393
289
  #
394
- # Example:
395
- # netmask = IPAdmin.minumum_size(:IPCount => 14) -> 28
290
+ # Examples:
291
+ # netmask = IPAdmin.minumum_size(14)
292
+ # netmask = IPAdmin.minumum_size(:IPCount => 65536, :Version => 6)
396
293
  #
397
294
  def minimum_size(options)
398
295
  version = 4
399
296
 
400
- if ( !options.kind_of?(Hash) )
401
- raise ArgumentError, "Hash expected but #{options.class} provided."
402
- end
403
-
404
- if ( !options.has_key?(:IPCount) )
405
- raise ArgumentError, "Missing argument: List."
406
- end
407
- ipcount = options[:IPCount]
297
+ if ( options.kind_of?(Hash) )
298
+ if ( !options.has_key?(:IPCount) )
299
+ raise ArgumentError, "Missing argument: List."
300
+ end
301
+ ipcount = options[:IPCount]
408
302
 
409
- if (options.has_key?(:Version))
410
- version = options[:Version]
303
+ if (options.has_key?(:Version))
304
+ version = options[:Version]
305
+ end
306
+ elsif ( options.kind_of?(Integer) )
307
+ ipcount = options
308
+ else
309
+ raise ArgumentError, "Integer or Hash expected but #{options.class} provided."
411
310
  end
412
311
 
413
312
  if (version == 4)
@@ -442,11 +341,10 @@ module_function :minimum_size
442
341
  # pack_ip_addr()
443
342
  #==============================================================================#
444
343
 
445
- # Convert IP addresses into an integer. No attempt at
446
- # validation is performed.
344
+ # Convert IP addresses into an integer.
447
345
  #
448
346
  # - Arguments:
449
- # * Hash with the following fields:
347
+ # * IP address as a String, or a Hash with the following fields:
450
348
  # - :IP -- IP address - String
451
349
  # - :Version -- IP version - Integer
452
350
  #
@@ -456,32 +354,39 @@ module_function :minimum_size
456
354
  # - Notes:
457
355
  # * Will attempt to auto-detect IP version if not provided
458
356
  #
459
- # Example:
460
- # pack_ip_addr(IP => '192.168.1.1')
461
- # pack_ip_addr(IP => 'ffff::1')
462
- # pack_ip_addr(IP => '::192.168.1.1')
357
+ # Examples:
358
+ # pack_ip_addr('192.168.1.1')
359
+ # pack_ip_addr(IP => 'ffff::1', :Version => 6)
360
+ # pack_ip_addr(::192.168.1.1')
463
361
  #
464
362
  def pack_ip_addr(options)
363
+ to_validate = {}
465
364
 
466
- if (!options.kind_of?(Hash))
467
- raise ArgumentError, "Expected Hash, but #{options.class} provided."
468
- end
469
-
470
- if (!options.has_key?(:IP))
471
- raise ArgumentError, "Missing argument: IP."
472
- end
473
- ip = options[:IP]
474
-
475
- if (options.has_key?(:Version))
476
- version = options[:Version]
477
- if (version != 4 && version != 6)
478
- raise ArgumentError, ":Version should be 4 or 6, but was '#{version}'."
365
+ if (options.kind_of?(Hash))
366
+ if (!options.has_key?(:IP))
367
+ raise ArgumentError, "Missing argument: IP."
479
368
  end
480
- end
369
+ ip = options[:IP]
370
+
371
+ if (options.has_key?(:Version))
372
+ version = options[:Version]
373
+ to_validate[:Version] = version
374
+ if (version != 4 && version != 6)
375
+ raise ArgumentError, ":Version should be 4 or 6, but was '#{version}'."
376
+ end
377
+ end
378
+ elsif
379
+ ip = options
380
+ else
381
+ raise ArgumentError, "String or Hash expected, but #{options.class} provided."
382
+ end
383
+ to_validate[:IP] = ip
481
384
 
482
-
483
385
  if ( ip.kind_of?(String) )
484
386
 
387
+ # validate
388
+ IPAdmin.validate_ip_addr(to_validate)
389
+
485
390
  # determine version if not provided
486
391
  if (!version)
487
392
  if ( ip =~ /\./ && ip !~ /:/ )
@@ -550,7 +455,7 @@ def pack_ip_addr(options)
550
455
  end
551
456
 
552
457
  else
553
- raise ArgumentError, "Argument :IP should be a String, but is a #{ip.class}."
458
+ raise ArgumentError, "IP address should be a String, but is a #{ip.class}."
554
459
  end
555
460
 
556
461
  return(packed_ip)
@@ -566,12 +471,12 @@ module_function :pack_ip_addr
566
471
  # pack_ip_netmask()
567
472
  #==============================================================================#
568
473
 
569
- # Convert IP netmask into an integer. No validation is performed. Netmask
570
- # may be in either CIDR (/yy) or extended (y.y.y.y) format. CIDR formatted
571
- # netmasks may either be a String or an Integer.
474
+ # Convert IP netmask into an integer.Netmask may be in either CIDR (/yy) or
475
+ # extended (y.y.y.y) format. CIDR formatted netmasks may either
476
+ # be a String or an Integer.
572
477
  #
573
478
  # - Arguments
574
- # * Hash with the following fields:
479
+ # * Netmask as a String, or a Integer, or a Hash with the following fields:
575
480
  # - :Netmask -- Netmask - String or Integer
576
481
  # - :Version -- IP version - Integer (optional)
577
482
  #
@@ -581,38 +486,45 @@ module_function :pack_ip_addr
581
486
  # - Notes:
582
487
  # * Version defaults to 4
583
488
  #
584
- # Example:
585
- # packed = IPAdmin.pack_ip_netmask(Netmask => '255.255.255.0')
586
- # packed = IPAdmin.pack_ip_netmask(Netmask => '24')
587
- # packed = IPAdmin.pack_ip_netmask(Netmask => 24)
588
- # packed = IPAdmin.pack_ip_netmask(Netmask => '/24')
489
+ # Examples:
490
+ # packed = IPAdmin.pack_ip_netmask('255.255.255.0')
491
+ # packed = IPAdmin.pack_ip_netmask('24')
492
+ # packed = IPAdmin.pack_ip_netmask(24)
493
+ # packed = IPAdmin.pack_ip_netmask('/24')
589
494
  # packed = IPAdmin.pack_ip_netmask(Netmask => '64', :Version => 6)
590
495
  #
591
496
  def pack_ip_netmask(options)
592
- if (!options.kind_of?(Hash))
593
- raise ArgumentError, "Expected Hash, but #{options.class} provided."
594
- end
497
+ all_f = 2**32-1
595
498
 
596
- if (!options.has_key?(:Netmask))
597
- raise ArgumentError, "Missing argument: Netmask."
598
- end
599
- netmask = options[:Netmask]
499
+ if (options.kind_of?(Hash))
500
+ if (!options.has_key?(:Netmask))
501
+ raise ArgumentError, "Missing argument: Netmask."
502
+ end
503
+ netmask = options[:Netmask]
504
+ to_validate = {:Netmask => netmask}
600
505
 
601
- if (options.has_key?(:Version))
602
- version = options[:Version]
603
- if (version != 4 && version != 6)
604
- raise ArgumentError, ":Version should be 4 or 6, but was '#{version}'."
605
- elsif (version == 6)
606
- all_f = 2**128-1
607
- else
608
- all_f = 2**32-1
506
+ if (options.has_key?(:Version))
507
+ version = options[:Version]
508
+ if (version != 4 && version != 6)
509
+ raise ArgumentError, ":Version should be 4 or 6, but was '#{version}'."
510
+ elsif (version == 6)
511
+ all_f = 2**128-1
512
+ else
513
+ all_f = 2**32-1
514
+ end
515
+ to_validate[:Version] = version
609
516
  end
517
+
518
+ elsif (options.kind_of?(String) || options.kind_of?(Integer))
519
+ netmask = options
520
+ to_validate = {:Netmask => netmask}
610
521
  else
611
- all_f = 2**32-1
522
+ raise ArgumentError, "String, Integer, or Hash expected, but #{options.class} provided."
612
523
  end
613
524
 
614
-
615
525
  if (netmask.kind_of?(String))
526
+ IPAdmin.validate_ip_netmask(to_validate)
527
+
616
528
  if(netmask =~ /\./)
617
529
  packed_netmask = IPAdmin.pack_ip_addr(:IP => netmask)
618
530
 
@@ -625,11 +537,14 @@ def pack_ip_netmask(options)
625
537
  netmask = netmask.to_i
626
538
  packed_netmask = all_f ^ (all_f >> netmask)
627
539
  end
540
+
628
541
  elsif (netmask.kind_of?(Integer))
542
+ to_validate[:Packed] = true
543
+ IPAdmin.validate_ip_netmask(to_validate)
629
544
  packed_netmask = all_f ^ (all_f >> netmask)
630
545
 
631
546
  else
632
- raise ArgumentError, "Argument :Netmask should be a String or Integer, but is a #{netmask.class}."
547
+ raise ArgumentError, "Netmask should be a String or Integer, but is a #{netmask.class}."
633
548
 
634
549
  end
635
550
 
@@ -646,36 +561,41 @@ module_function :pack_ip_netmask
646
561
  # range()
647
562
  #==============================================================================#
648
563
 
649
- # Given two IPAdmin::CIDR objects of the same version, return all IP
650
- # addresses between them (non-inclusive).
564
+ # Given two CIDR addresses or IPAdmin::CIDR objects of the same version,
565
+ # return all IP addresses between them.
651
566
  #
652
567
  # - Arguments:
653
- # * Hash with the following fields:
568
+ # * Array of (2)CIDR addresses or IPAdmin::CIDR objects, or a Hash
569
+ # with the following fields:
654
570
  # - :Bitstep -- enumerate in X sized steps - Integer (optional)
655
- # - :Boundaries -- array of (2) CIDR objects
571
+ # - :Boundaries -- array of (2) CIDR addresses or IPAdmin::CIDR objects
572
+ # - :Inclusive -- if true, include boundaries in returned data
656
573
  # - :Limit -- limit returned list to X number of items - Integer (optional)
657
574
  # - :Objectify -- if true, return CIDR objects (optional)
658
575
  # - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
659
576
  #
660
577
  # - Returns:
661
- # * Array of Strings or CIDR objects
578
+ # * Array of CIDR address Strings or IPAdmin::CIDR objects
662
579
  #
663
580
  # - Notes:
664
581
  # * IPAdmin.range will use the original IP address passed during the initialization
665
- # of the CIDR objects. This IP can be found using the CIDR.ip() method.
582
+ # of the IPAdmin::CIDR objects, or the base address of any CIDR addresses passed.
583
+ # * The default behavior is to be non-inclusive (dont include boundaries as part of returned data)
666
584
  #
667
- # Example:
668
- # list = IPAdmin.range(:Boundaries => [cidr1,cidr2])
585
+ # Examples:
586
+ # list = IPAdmin.range(:Boundaries => [cidr1,cidr2], :Limit => 10)
587
+ # list = IPAdmin.range(['192.168.1.0','192.168.1.10']
669
588
  #
670
589
  def range(options)
671
590
  list = []
672
591
  bitstep = 1
673
592
  objectify = false
674
593
  short = false
594
+ inclusive = false
675
595
  limit = nil
676
596
 
677
597
  # check options
678
- if (options)
598
+ if (options.kind_of?(Hash))
679
599
  if ( !options.has_key?(:Boundaries) )
680
600
  raise ArgumentError, "Missing argument: Boundaries."
681
601
  end
@@ -698,16 +618,39 @@ def range(options)
698
618
  if( options.has_key?(:Short) && options[:Short] == true )
699
619
  short = true
700
620
  end
621
+
622
+ if( options.has_key?(:Inclusive) && options[:Inclusive] == true )
623
+ inclusive = true
624
+ end
701
625
 
702
626
  if( options.has_key?(:Limit) )
703
627
  limit = options[:Limit]
704
628
  end
629
+
630
+ elsif(options.kind_of?(Array))
631
+ (cidr1,cidr2) = options
632
+ else
633
+ raise ArgumentError, "Array or Hash expected but #{options.class} provided."
634
+ end
635
+
636
+ # if cidr1/cidr2 are not CIDR objects, then attempt to create
637
+ # cidr objects from them
638
+ if ( !cidr1.kind_of?(IPAdmin::CIDR) )
639
+ begin
640
+ cidr1 = IPAdmin::CIDR.new(:CIDR => cidr1)
641
+ rescue Exception => error
642
+ raise ArgumentError, "First argument of :Boundaries raised the following " +
643
+ "errors: #{error}"
644
+ end
705
645
  end
706
646
 
707
- # check our objects
708
- if (!cidr1.kind_of?(IPAdmin::CIDR) && !cidr2.kind_of?(IPAdmin::CIDR))
709
- raise ArgumentError, "One or more values provided under :Boundaries "+
710
- "is not a valid IPAdmin::CIDR object."
647
+ if ( !cidr2.kind_of?(IPAdmin::CIDR))
648
+ begin
649
+ cidr2 = IPAdmin::CIDR.new(:CIDR => cidr2)
650
+ rescue Exception => error
651
+ raise ArgumentError, "Second argument of :Boundaries raised the following " +
652
+ "errors: #{error}"
653
+ end
711
654
  end
712
655
 
713
656
  # check version, store & sort
@@ -720,8 +663,15 @@ def range(options)
720
663
  end
721
664
 
722
665
  # dump our range
723
- my_ip = boundaries[0] + 1
724
- until (my_ip >= boundaries[1])
666
+ if (!inclusive)
667
+ my_ip = boundaries[0] + 1
668
+ end_ip = boundaries[1]
669
+ else
670
+ my_ip = boundaries[0]
671
+ end_ip = boundaries[1] + 1
672
+ end
673
+
674
+ until (my_ip >= end_ip)
725
675
  if (!objectify)
726
676
  my_ip_s = IPAdmin.unpack_ip_addr(:Integer => my_ip, :Version => version)
727
677
  my_ips = IPAdmin.shorten(my_ips) if (short && version == 6)
@@ -754,13 +704,13 @@ module_function :range
754
704
  # The address should not contain a netmask.
755
705
  #
756
706
  # - Arguments:
757
- # * String
707
+ # * IP address as a String
758
708
  #
759
709
  # - Returns:
760
710
  # * String
761
711
  #
762
- # Example:
763
- # short = IPAdmin.shorten('fec0:0000:0000:0000:0000:0000:0000:0001') --> 'fec0::1'
712
+ # Examples:
713
+ # short = IPAdmin.shorten('fec0:0000:0000:0000:0000:0000:0000:0001')
764
714
  #
765
715
  def shorten(addr)
766
716
 
@@ -846,21 +796,22 @@ module_function :shorten
846
796
  # sort()
847
797
  #==============================================================================#
848
798
 
849
- # Given a list of IPAdmin::CIDR or NetStruct objects
799
+ # Given a list of CIDR addresses or IPAdmin::CIDR objects,
850
800
  # sort them from lowest to highest by Network/Netmask.
851
801
  #
852
802
  # - Arguments:
853
- # * Array of CIDR or NetStruct objects
803
+ # * Array of CIDR addresses or IPAdmin::CIDR objects
854
804
  #
855
805
  # - Returns:
856
- # * Array
806
+ # * Array of CIDR address Strings or IPAdmin::CIDR objects
857
807
  #
858
808
  # - Notes:
859
809
  # * IPAdmin.sort will use the original IP address passed during the initialization
860
- # of the CIDR objects. This IP can be found using the CIDR.ip() method.
810
+ # of any IPAdmin::CIDR objects, or the base address of any CIDR addresses passed.
861
811
  #
862
- # Example:
863
- # sorted = IPAdmin.sort(list)
812
+ # Examples:
813
+ # sorted = IPAdmin.sort([cidr1,cidr2])
814
+ # sorted = IPAdmin.sort(['192.168.1.32/27','192.168.1.0/27'])
864
815
  #
865
816
  def sort(list)
866
817
 
@@ -872,33 +823,35 @@ def sort(list)
872
823
 
873
824
  # make sure all are valid types of the same IP version
874
825
  version = nil
875
- list.each do |obj|
876
- unless (obj.kind_of?(IPAdmin::CIDR) || obj.kind_of?(IPAdmin::NetStruct) )
877
- raise ArgumentError, "Expected IPAdmin::CIDR or NetStruct " +
878
- "object but #{obj.class} provided."
826
+ cidr_hash = {}
827
+ list.each do |cidr|
828
+ if (!cidr.kind_of?(IPAdmin::CIDR))
829
+ begin
830
+ new_cidr = IPAdmin::CIDR.new(cidr)
831
+ rescue Exception => error
832
+ raise ArgumentError, "An element of the provided Array " +
833
+ "raised the following errors: #{error}"
834
+ end
835
+ else
836
+ new_cidr = cidr
879
837
  end
880
-
881
- version = obj.version if (!version)
882
- unless (obj.version == version)
883
- raise "Provided objects must all be of the same IP version."
838
+ cidr_hash[new_cidr] = cidr
839
+
840
+ version = new_cidr.version if (!version)
841
+ unless (new_cidr.version == version)
842
+ raise "Provided CIDR addresses must all be of the same IP version."
884
843
  end
885
844
  end
886
845
 
887
- # create unsorted_list from list
888
- unsorted_list = []
889
- list.each do |obj|
890
- unsorted_list.push(IPAdmin.create_net_struct(obj))
891
- end
892
-
893
846
  # sort by network. if networks are equal, sort by netmask.
894
847
  sorted_list = []
895
- unsorted_list.each do |entry|
848
+ cidr_hash.each_key do |entry|
896
849
  index = 0
897
850
  sorted_list.each do
898
- if(entry.network < (sorted_list[index]).network)
851
+ if(entry.packed_network < (sorted_list[index]).packed_network)
899
852
  break
900
- elsif (entry.network == (sorted_list[index]).network)
901
- if (entry.netmask < (sorted_list[index]).netmask)
853
+ elsif (entry.packed_network == (sorted_list[index]).packed_network)
854
+ if (entry.packed_netmask < (sorted_list[index]).packed_netmask)
902
855
  break
903
856
  end
904
857
  end
@@ -906,15 +859,12 @@ def sort(list)
906
859
  end
907
860
  sorted_list.insert(index, entry)
908
861
  end
862
+
863
+ # return original values passed
864
+ ret_list = []
865
+ sorted_list.each {|x| ret_list.push(cidr_hash[x])}
909
866
 
910
- # replace sorted_list entries with their .object
911
- index = 0
912
- sorted_list.length.times do
913
- sorted_list[index] = (sorted_list[index]).object
914
- index += 1
915
- end
916
-
917
- return(sorted_list)
867
+ return(ret_list)
918
868
  end
919
869
  module_function :sort
920
870
 
@@ -927,11 +877,10 @@ module_function :sort
927
877
  # unpack_ip_addr()
928
878
  #==============================================================================#
929
879
 
930
- # Unack a packed IP address back into a printable string. No attempt at
931
- # validation is performed.
880
+ # Unack a packed IP address back into a printable string.
932
881
  #
933
882
  # - Arguments:
934
- # * Hash with the following fields:
883
+ # * Integer or a Hash with the following fields:
935
884
  # - :Integer -- Integer representaion of an IP address
936
885
  # - :Version -- IP version - Integer (optional)
937
886
  # - :IPv4Mapped -- if true, unpack IPv6 as an IPv4 mapped address (optional)
@@ -942,35 +891,44 @@ module_function :sort
942
891
  # - Notes:
943
892
  # * IP version will attempt to be auto-detected if not provided
944
893
  #
945
- # Example:
894
+ # Examples:
895
+ # unpacked = IPAdmin.unpack_ip_addr(3232235906)
946
896
  # unpacked = IPAdmin.unpack_ip_addr(:Integer => packed)
947
897
  #
948
898
  def unpack_ip_addr(options)
949
899
  ipv4_mapped = false
900
+ to_validate = {}
950
901
 
951
- if (!options.kind_of?(Hash))
952
- raise ArgumentError, "Expected Hash, but #{options.class} provided."
953
- end
902
+ if (options.kind_of?(Hash))
903
+ if (!options.has_key?(:Integer))
904
+ raise ArgumentError, "Missing argument: Integer."
905
+ end
906
+ packed_ip = options[:Integer]
907
+
908
+ if (options.has_key?(:Version))
909
+ version = options[:Version]
910
+ to_validate[:Version] = version
911
+ if (version != 4 && version != 6)
912
+ raise ArgumentError, ":Version should be 4 or 6, but was '#{version}'."
913
+ end
914
+ end
954
915
 
955
- if (!options.has_key?(:Integer))
956
- raise ArgumentError, "Missing argument: Integer."
916
+ if (options.has_key?(:IPv4Mapped) && options[:IPv4Mapped] == true)
917
+ ipv4_mapped = true
918
+ end
919
+ elsif (options.kind_of?(Integer))
920
+ packed_ip = options
921
+ else
922
+ raise ArgumentError, "Integer or Hash expected, but #{options.class} provided."
957
923
  end
958
- packed_ip = options[:Integer]
959
924
 
960
925
  if (!packed_ip.kind_of?(Integer))
961
- raise ArgumentError, "Expected Integer, but #{options.class} provided for argument: Integer."
962
- end
963
-
964
- if (options.has_key?(:Version))
965
- version = options[:Version]
966
- if (version != 4 && version != 6)
967
- raise ArgumentError, ":Version should be 4 or 6, but was '#{version}'."
968
- end
926
+ raise ArgumentError, "Packed IP should be an Integer, but was a #{options.class}."
969
927
  end
970
928
 
971
- if (options.has_key?(:IPv4Mapped) && options[:IPv4Mapped] == true)
972
- ipv4_mapped = true
973
- end
929
+ # validate
930
+ to_validate[:IP] = packed_ip
931
+ IPAdmin.validate_ip_addr(to_validate)
974
932
 
975
933
  # set version if not set
976
934
  if (!version)
@@ -1030,38 +988,48 @@ module_function :unpack_ip_addr
1030
988
  #==============================================================================#
1031
989
 
1032
990
  # Unack a packed IP netmask into a integer representing the number of
1033
- # bits in the CIDR mask. No attempt at validation is performed.
991
+ # bits in the CIDR mask.
1034
992
  #
1035
993
  # - Arguments:
1036
- # * Hash with the following fields:
994
+ # * Integer or a Hash with the following fields:
1037
995
  # - :Integer -- Integer representation of an IP Netmask
1038
996
  #
1039
997
  # - Returns:
1040
998
  # * Integer
1041
999
  #
1042
- # Example:
1000
+ # Examples:
1001
+ # unpacked = IPAdmin.unpack_ip_netmask(0xfffffffe)
1043
1002
  # unpacked = IPAdmin.unpack_ip_netmask(:Integer => packed)
1044
1003
  #
1045
1004
  def unpack_ip_netmask(options)
1046
- if (!options.kind_of?(Hash))
1047
- raise ArgumentError, "Expected Hash, but #{options.class} provided."
1048
- end
1049
1005
 
1050
- if (!options.has_key?(:Integer))
1051
- raise ArgumentError, "Missing argument: Integer."
1052
- end
1053
- packed_netmask = options[:Integer]
1006
+ if (options.kind_of?(Hash))
1007
+ if (!options.has_key?(:Integer))
1008
+ raise ArgumentError, "Missing argument: Integer."
1009
+ end
1010
+ packed_netmask = options[:Integer]
1011
+
1012
+ if (!packed_netmask.kind_of?(Integer))
1013
+ raise ArgumentError, "Packed netmask should be an Integer, but is a #{packed_netmask.class}."
1014
+ end
1015
+
1016
+ elsif (options.kind_of?(Integer))
1017
+ packed_netmask = options
1018
+
1019
+ else
1020
+ raise ArgumentError, "Integer or Hash expected, but #{options.class} provided."
1021
+ end
1054
1022
 
1055
- if (!packed_netmask.kind_of?(Integer))
1056
- raise ArgumentError, "Argument :Integer should be an Integer, but is a #{packed_netmask.class}."
1057
- end
1058
1023
 
1059
1024
  if (packed_netmask < 2**32)
1060
1025
  mask = 32
1026
+ IPAdmin.validate_ip_netmask(:Netmask => packed_netmask, :Packed => true, :Version => 4)
1061
1027
  else
1028
+ IPAdmin.validate_ip_netmask(:Netmask => packed_netmask, :Packed => true, :Version => 6)
1062
1029
  mask = 128
1063
1030
  end
1064
1031
 
1032
+
1065
1033
  mask.times do
1066
1034
  if ( (packed_netmask & 1) == 1)
1067
1035
  break
@@ -1087,13 +1055,13 @@ module_function :unpack_ip_netmask
1087
1055
  # notation. The address should not contain a netmask.
1088
1056
  #
1089
1057
  # - Arguments:
1090
- # * String
1058
+ # * IP address as a String
1091
1059
  #
1092
1060
  # - Returns:
1093
1061
  # * String
1094
1062
  #
1095
- # Example:
1096
- # long = IPAdmin.unshorten('fec0::1') --> 'fec0:0000:0000:0000:0000:0000:0000:0001'
1063
+ # Examples:
1064
+ # long = IPAdmin.unshorten('fec0::1')
1097
1065
  #
1098
1066
  def unshorten(addr)
1099
1067
 
@@ -1128,24 +1096,27 @@ module_function :unshorten
1128
1096
  # Validate an EUI-48 or EUI-64 address.
1129
1097
  #
1130
1098
  # - Arguments
1131
- # * Hash with the following fields:
1099
+ # * EUI address as a String, or a Hash with the following fields:
1132
1100
  # - :EUI -- Address to validate - String
1133
1101
  #
1134
1102
  # - Returns:
1135
1103
  # * True
1136
1104
  #
1137
- # - Example:
1105
+ # Examples:
1106
+ # * IPAdmin.validate_eui('01-00-5e-12-34-56')
1138
1107
  # * IPAdmin.validate_eui(:EUI => '01-00-5e-12-34-56')
1139
1108
  #
1140
1109
  def validate_eui(options)
1141
- if (!options.kind_of? Hash)
1142
- raise ArgumentError, "Expected Hash, but #{options.class} provided."
1143
- end
1144
-
1145
- if (!options.has_key?(:EUI))
1146
- raise ArgumentError, "Missing argument: EUI."
1110
+ if (options.kind_of? Hash)
1111
+ if (!options.has_key?(:EUI))
1112
+ raise ArgumentError, "Missing argument: EUI."
1113
+ end
1114
+ eui = options[:EUI]
1115
+ elsif (options.kind_of? String)
1116
+ eui = options
1117
+ else
1118
+ raise ArgumentError, "String or Hash expected, but #{options.class} provided."
1147
1119
  end
1148
- eui = options[:EUI]
1149
1120
 
1150
1121
  if (eui.kind_of?(String))
1151
1122
  # check for invalid characters
@@ -1174,8 +1145,7 @@ def validate_eui(options)
1174
1145
  end
1175
1146
 
1176
1147
  else
1177
- raise ArgumentError, "Expected String, but #{eui.class} " +
1178
- "provided for argument :EUI."
1148
+ raise ArgumentError, "EUI address should be a String, but was a#{eui.class}."
1179
1149
  end
1180
1150
  return(true)
1181
1151
  end
@@ -1193,7 +1163,7 @@ module_function :validate_eui
1193
1163
  # Validate an IP address. The address should not contain a netmask.
1194
1164
  #
1195
1165
  # - Arguments
1196
- # * Hash with the following fields:
1166
+ # * IP address as a String or Integer, or a Hash with the following fields:
1197
1167
  # - :IP -- IP address to validate - String or Integer
1198
1168
  # - :Version -- IP version - Integer (optional)
1199
1169
  #
@@ -1203,9 +1173,9 @@ module_function :validate_eui
1203
1173
  # - Notes:
1204
1174
  # * IP version will attempt to be auto-detected if not provided
1205
1175
  #
1206
- # Example:
1207
- # validate_ip_addr(IP => '192.168.1.1')
1208
- # validate_ip_addr(IP => 'ffff::1')
1176
+ # Examples:
1177
+ # validate_ip_addr('192.168.1.1')
1178
+ # validate_ip_addr(IP => 'ffff::1', :Version => 6)
1209
1179
  # validate_ip_addr(IP => '::192.168.1.1')
1210
1180
  # validate_ip_addr(IP => 0xFFFFFF)
1211
1181
  # validate_ip_addr(IP => 2**128-1)
@@ -1213,20 +1183,22 @@ module_function :validate_eui
1213
1183
  #
1214
1184
  def validate_ip_addr(options)
1215
1185
 
1216
- if (!options.kind_of?(Hash))
1217
- raise ArgumentError, "Expected Hash, but #{options.class} provided."
1218
- end
1219
-
1220
- if (!options.has_key?(:IP))
1221
- raise ArgumentError, "Missing argument: IP."
1222
- end
1223
- ip = options[:IP]
1186
+ if (options.kind_of?(Hash))
1187
+ if (!options.has_key?(:IP))
1188
+ raise ArgumentError, "Missing argument: IP."
1189
+ end
1190
+ ip = options[:IP]
1224
1191
 
1225
- if (options.has_key?(:Version))
1226
- version = options[:Version]
1227
- if (version != 4 && version != 6)
1228
- raise ArgumentError, ":Version should be 4 or 6, but was '#{version}'."
1192
+ if (options.has_key?(:Version))
1193
+ version = options[:Version]
1194
+ if (version != 4 && version != 6)
1195
+ raise ArgumentError, ":Version should be 4 or 6, but was '#{version}'."
1196
+ end
1229
1197
  end
1198
+ elsif (options.kind_of?(String) || options.kind_of?(Integer))
1199
+ ip = options
1200
+ else
1201
+ raise ArgumentError, "String or Hash expected, but #{options.class} provided."
1230
1202
  end
1231
1203
 
1232
1204
  if ( ip.kind_of?(String) )
@@ -1358,7 +1330,7 @@ module_function :validate_ip_addr
1358
1330
  # Validate IP Netmask.
1359
1331
  #
1360
1332
  # - Arguments:
1361
- # * Hash with the following fields:
1333
+ # * Netmask as a String or Integer, or a Hash with the following fields:
1362
1334
  # - :Netmask -- Netmask to validate - String or Integer
1363
1335
  # - :Packed -- if true, the provided Netmask is a packed Integer
1364
1336
  # - :Version -- IP version - Integer (optional)
@@ -1369,42 +1341,43 @@ module_function :validate_ip_addr
1369
1341
  # - Notes:
1370
1342
  # * Version defaults to 4 if not specified.
1371
1343
  #
1372
- # Example:
1373
- # IPAdmin.validate_ip_netmask(:Netmask => '/32')
1374
- # IPAdmin.validate_ip_netmask(:Netmask => 32)
1344
+ # Examples:
1345
+ # IPAdmin.validate_ip_netmask('/32')
1346
+ # IPAdmin.validate_ip_netmask(32)
1375
1347
  # IPAdmin.validate_ip_netmask(:Netmask => 0xffffffff, :Packed => true)
1376
1348
  #
1377
1349
  def validate_ip_netmask(options)
1378
1350
  packed = false
1351
+ version = 4
1352
+ max_bits = 32
1379
1353
 
1380
- if (!options.kind_of?(Hash))
1381
- raise ArgumentError, "Expected Hash, but #{options.class} provided."
1382
- end
1383
-
1384
- if (!options.has_key?(:Netmask))
1385
- raise ArgumentError, "Missing argument: Netmask."
1386
- end
1387
- netmask = options[:Netmask]
1354
+ if (options.kind_of?(Hash))
1355
+ if (!options.has_key?(:Netmask))
1356
+ raise ArgumentError, "Missing argument: Netmask."
1357
+ end
1358
+ netmask = options[:Netmask]
1388
1359
 
1389
- if (options.has_key?(:Packed) && options[:Packed] == true)
1390
- packed = true
1391
- end
1360
+ if (options.has_key?(:Packed) && options[:Packed] == true)
1361
+ packed = true
1362
+ end
1392
1363
 
1393
- if (options.has_key?(:Version))
1394
- version = options[:Version]
1395
- if (version != 4 && version != 6)
1396
- raise ArgumentError, ":Version should be 4 or 6, but was '#{version}'."
1397
- elsif (version == 6)
1398
- max_bits = 128
1399
- else
1400
- max_bits = 32
1364
+ if (options.has_key?(:Version))
1365
+ version = options[:Version]
1366
+ if (version != 4 && version != 6)
1367
+ raise ArgumentError, ":Version should be 4 or 6, but was '#{version}'."
1368
+ elsif (version == 6)
1369
+ max_bits = 128
1370
+ else
1371
+ max_bits = 32
1372
+ end
1401
1373
  end
1374
+
1375
+ elsif (options.kind_of?(String) || options.kind_of?(Integer))
1376
+ netmask = options
1402
1377
  else
1403
- version = 4
1404
- max_bits = 32
1378
+ raise ArgumentError, "String, Integer, or Hash expected, but #{options.class} provided."
1405
1379
  end
1406
1380
 
1407
-
1408
1381
  if (netmask.kind_of?(String))
1409
1382
  if(netmask =~ /\./)
1410
1383
  all_f = 2**32-1
@@ -1490,13 +1463,11 @@ module_function :validate_ip_netmask
1490
1463
  # to anyone.
1491
1464
  #
1492
1465
  # Description of fields:
1493
- # * network - Integer representing an IP address
1494
- # * netmask - Integer representing IP netmask
1495
- # * version - Integer representing an IP version
1496
- # * object - holds an IPAdmin class object
1497
- # * subnets - an array of children NetStruct objects
1466
+ # * cidr - IPAdmin::CIDR object
1467
+ # * parent - parent NetStruct in tree
1468
+ # * children - Array of children NetStruct objects
1498
1469
  #
1499
- NetStruct = Struct.new(:network, :netmask, :version, :object, :subnets)
1470
+ NetStruct = Struct.new(:cidr, :parent, :children)
1500
1471
 
1501
1472
  #======================================#
1502
1473
  #