netaddr 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of netaddr might be problematic. Click here for more details.

data/changelog CHANGED
@@ -1,16 +1,25 @@
1
1
 
2
2
  ==Version
3
- *1.2.0*
3
+ ====1.3.0
4
4
 
5
+ ===New Features
6
+ * added CIDR#[]
7
+ * added CIDR#succ (CIDR objects may now be used as args for the standard Ruby Range class)
8
+ * added CIDR#allocate_rfc3531
9
+ * added CIDR#to_i
10
+ * added CIDRv6.unique_local
11
+ * added EUI48#to_eui64
12
+ * added EUI#to_i
13
+ * added EUI#to_s
5
14
 
6
- ===Known Issues
15
+ ===Changes
16
+ * deprecated 'packed' methods
7
17
 
8
- * users may directly modify CIDR objects stored within a Tree,
9
- essentially invalidating the structure of that Tree
10
18
 
19
+ ==Version
20
+ ====1.2.0
11
21
 
12
22
  ===Changes
13
-
14
23
  * CIDRv4#new and CIDRv6#new methods have been changed for the sake of speed improvements.
15
24
  Please use the CIDR#create method instead.
16
25
  * changes to CIDR#wildcard_mask
@@ -20,7 +29,6 @@
20
29
 
21
30
 
22
31
  ===New Features
23
-
24
32
  * speed improvements
25
33
  * added CIDR#set_wildcard_mask
26
34
  * added <=>, >, <, == methods to CIDR
data/lib/cidr.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,21 +10,21 @@ module NetAddr
10
10
  #
11
11
  #A class & series of methods for creating and manipulating CIDR network
12
12
  #addresses. Both IPv4 and IPv6 are supported.
13
- #
13
+ #
14
14
  #This class accepts a CIDR address, via the CIDR.create method,
15
15
  #in (x.x.x.x/yy or xxxx::/yy) format for IPv4 and IPv6, or (x.x.x.x/y.y.y.y) for IPv4.
16
16
  #CIDR.create then creates either a CIDRv4 or CIDRv6 object. An optional tag hash may be
17
17
  #provided with each CIDR as a way of adding custom labels.
18
- #
18
+ #
19
19
  #Upon initialization, the IP version is auto-detected and assigned to the
20
20
  #CIDR. The original IP/Netmask passed within the CIDR is stored and then
21
21
  #used to determine the confines of the CIDR block. Various properties of the
22
22
  #CIDR block are accessible via several different methods. There are also
23
23
  #methods for modifying the CIDR or creating new derivative CIDR's.
24
- #
24
+ #
25
25
  #An example CIDR object is as follows:
26
26
  # NetAddr::CIDR.create('192.168.1.20/24')
27
- #
27
+ #
28
28
  #This would create a CIDR object (192.168.1.0/24) with the following properties:
29
29
  # version = 4
30
30
  # base network = 192.168.1.0
@@ -32,7 +32,7 @@ module NetAddr
32
32
  # netmask = /24 (255.255.255.0)
33
33
  # size = 256 IP addresses
34
34
  # broadcast = 192.168.1.255
35
- #
35
+ #
36
36
  #You can see how the CIDR object is based around the entire IP space
37
37
  #defined by the provided IP/Netmask pair, and not necessarily the individual
38
38
  #IP address itself.
@@ -70,52 +70,6 @@ private_class_method :new
70
70
  @tag = new_tag
71
71
  end
72
72
 
73
- #==============================================================================#
74
- # initialize()
75
- #==============================================================================#
76
-
77
- # This method performs absolutely no error checking, and is meant to be used only by
78
- # other internal methods for the sake of the speedier creation of CIDR objects.
79
- # Please consider using #create unless you know what you are doing with 100% certainty.
80
- #
81
- #===Arguments:
82
- #* ip - Integer representing an ip address
83
- #* netmask - Integer representing a binary mask
84
- #* tag - Hash used to append custom tags to CIDR
85
- #* wildcard_mask - Integer representing a binary mask
86
- #* wildcard_mask_bit_flipped - indicates whether or not the wildcard_mask is bit-flipped or not
87
- #
88
- def initialize(ip, netmask=nil, tag={}, wildcard_mask=nil, wildcard_mask_bit_flipped=false)
89
- @ip = ip
90
-
91
- if ( self.kind_of?(NetAddr::CIDRv4) )
92
- @version = 4
93
- @address_len = 32
94
- else
95
- @version = 6
96
- @address_len = 128
97
- end
98
- @all_f = 2**@address_len - 1
99
-
100
- if (netmask)
101
- @netmask = netmask
102
- else
103
- @netmask = 2**@address_len - 1
104
- end
105
-
106
- @network = (@ip & @netmask)
107
- @hostmask = @netmask ^ @all_f
108
- @tag = tag
109
-
110
- if (!wildcard_mask)
111
- @wildcard_mask = @netmask
112
- else
113
- @wildcard_mask = wildcard_mask
114
- @wildcard_mask = ~@wildcard_mask if (wildcard_mask_bit_flipped)
115
- end
116
-
117
- end
118
-
119
73
  #==============================================================================#
120
74
  # create()
121
75
  #==============================================================================#
@@ -124,13 +78,13 @@ private_class_method :new
124
78
  #Create a new CIDRv4 or CIDRv6 object.
125
79
  #CIDR formatted netmasks take precedence over extended formatted ones.
126
80
  #CIDR address defaults to a host network (/32 or /128) if netmask not provided.
127
- #:PackedNetmask takes precedence over netmask given within CIDR addresses.
81
+ #:Mask takes precedence over netmask given within CIDR addresses.
128
82
  #Version will be auto-detected if not specified.
129
83
  #
130
84
  # NetAddr::CIDR.create('192.168.1.1/24')
131
85
  # NetAddr::CIDR.create('192.168.1.1 255.255.255.0')
132
86
  # NetAddr::CIDR.create(0x0a010001,
133
- # :PackedNetmask => 0xffffff00
87
+ # :Mask => 0xffffff00
134
88
  # :Version => 4)
135
89
  # NetAddr::CIDR.create('192.168.1.1',
136
90
  # :WildcardMask => ['0.7.0.255', true])
@@ -144,9 +98,9 @@ private_class_method :new
144
98
  # NetAddr::CIDR.create('::ffff:192.168.1.1/96')
145
99
  #
146
100
  #===Arguments:
147
- #* addr = CIDR address as a String, or a packed IP address as an Integer
101
+ #* addr = CIDR address as a String, or an IP address as an Integer
148
102
  #* options = Hash with the following keys:
149
- # :PackedNetmask -- Integer representation of an IP Netmask
103
+ # :Mask -- Integer representing a binary IP Netmask
150
104
  # :Version -- IP version - Integer
151
105
  # :Tag -- Custom descriptor tag - Hash, tag => value.
152
106
  # :WildcardMask -- 2 element Array. First element contains a special bit mask used for
@@ -154,10 +108,10 @@ private_class_method :new
154
108
  # bit mask is bit flipped.
155
109
  #
156
110
  def CIDR.create(addr, options=nil)
157
- known_args = [:PackedNetmask, :Version, :Tag, :WildcardMask]
111
+ known_args = [:Mask, :Version, :Tag, :WildcardMask]
158
112
  ip, netmask, tag = nil, nil, {}
159
113
  version, wildcard_mask ,wildcard_mask_bit_flipped = nil, nil, false
160
- packed_netmask, all_f = nil, nil
114
+ netmask_int, all_f = nil, nil
161
115
 
162
116
  # validate options
163
117
  if (options)
@@ -165,10 +119,10 @@ private_class_method :new
165
119
  "#{options.class} provided." if (!options.kind_of?(Hash) )
166
120
  NetAddr.validate_args(options.keys,known_args)
167
121
 
168
- if (options.has_key?(:PackedNetmask))
169
- packed_netmask = options[:PackedNetmask]
170
- raise ArgumentError, "Expected Integer, but #{packed_netmask.class} " +
171
- "provided for option :PackedNetmask." if (!packed_netmask.kind_of?(Integer))
122
+ if (options.has_key?(:Mask))
123
+ netmask_int = options[:Mask]
124
+ raise ArgumentError, "Expected Integer, but #{netmask_int.class} " +
125
+ "provided for option :Mask." if (!netmask_int.kind_of?(Integer))
172
126
  end
173
127
 
174
128
  if (options.has_key?(:Tag))
@@ -239,10 +193,10 @@ private_class_method :new
239
193
  all_f = 2**32-1
240
194
  all_f = 2**128-1 if (version == 6)
241
195
 
242
- # set netmask. packed_netmask takes precedence. set to all_f if no netmask provided
243
- if (packed_netmask)
244
- NetAddr.validate_netmask_int(packed_netmask,version,true)
245
- netmask = packed_netmask
196
+ # set netmask. netmask_int takes precedence. set to all_f if no netmask provided
197
+ if (netmask_int)
198
+ NetAddr.validate_netmask_int(netmask_int,version,true)
199
+ netmask = netmask_int
246
200
  elsif (netmask)
247
201
  NetAddr.validate_netmask_str(netmask,version)
248
202
  netmask = NetAddr.netmask_str_to_int(netmask, version)
@@ -268,22 +222,70 @@ private_class_method :new
268
222
  end
269
223
 
270
224
  #==============================================================================#
271
- # <=>()
225
+ # initialize()
226
+ #==============================================================================#
227
+
228
+ # This method performs absolutely no error checking, and is meant to be used only by
229
+ # other internal methods for the sake of the speedier creation of CIDR objects.
230
+ # Please consider using #create unless you know what you are doing with 100% certainty.
231
+ #
232
+ #===Arguments:
233
+ #* ip - Integer representing an ip address
234
+ #* netmask - Integer representing a binary netmask
235
+ #* tag - Hash used to append custom tags to CIDR
236
+ #* wildcard_mask - Integer representing a binary mask
237
+ #* wildcard_mask_bit_flipped - indicates whether or not the wildcard_mask is bit-flipped or not
238
+ #
239
+ def initialize(ip, netmask=nil, tag={}, wildcard_mask=nil, wildcard_mask_bit_flipped=false)
240
+ @ip = ip
241
+
242
+ if ( self.kind_of?(NetAddr::CIDRv4) )
243
+ @version = 4
244
+ @address_len = 32
245
+ else
246
+ @version = 6
247
+ @address_len = 128
248
+ end
249
+ @all_f = 2**@address_len - 1
250
+
251
+ if (netmask)
252
+ @netmask = netmask
253
+ else
254
+ @netmask = 2**@address_len - 1
255
+ end
256
+
257
+ @network = (@ip & @netmask)
258
+ @hostmask = @netmask ^ @all_f
259
+ @tag = tag
260
+
261
+ if (!wildcard_mask)
262
+ @wildcard_mask = @netmask
263
+ else
264
+ @wildcard_mask = wildcard_mask
265
+ @wildcard_mask = ~@wildcard_mask if (wildcard_mask_bit_flipped)
266
+ end
267
+
268
+ end
269
+
270
+ #==============================================================================#
271
+ # <()
272
272
  #==============================================================================#
273
273
 
274
274
  #===Synopsis
275
- #Compare the sort order of the current CIDR with a provided CIDR and return:
276
- #* 1 if the current CIDR is greater than the provided CIDR
277
- #* 0 if the current CIDR and the provided CIDR are equal (base address and netmask are equal)
278
- #* -1 if the current CIDR is less than the provided CIDR
275
+ #Compare the sort order of the current CIDR with a provided CIDR and return true
276
+ #if current CIDR is less than provided CIDR.
277
+ #
278
+ # Example:
279
+ # cidr = NetAddr::CIDR.create('192.168.1.0/24')
280
+ # cidr < '192.168.2.0/24' => true
279
281
  #
280
282
  #===Arguments:
281
283
  #* CIDR address or NetAddr::CIDR object
282
284
  #
283
285
  #===Returns:
284
- #* Integer
286
+ #* true or false
285
287
  #
286
- def <=>(cidr)
288
+ def <(cidr)
287
289
  if (!cidr.kind_of?(NetAddr::CIDR))
288
290
  begin
289
291
  cidr = NetAddr::CIDR.create(cidr)
@@ -299,26 +301,35 @@ private_class_method :new
299
301
  end
300
302
 
301
303
  # compare
302
- comparasin = NetAddr.cidr_gt_lt(self,cidr)
304
+ lt = false
305
+ lt = true if ( NetAddr.cidr_gt_lt(self,cidr) == -1)
303
306
 
304
- return(comparasin)
307
+ return(lt)
305
308
  end
306
309
 
307
310
  #==============================================================================#
308
- # >()
311
+ # <=>()
309
312
  #==============================================================================#
310
313
 
311
314
  #===Synopsis
312
- #Compare the sort order of the current CIDR with a provided CIDR and return true
313
- #if current CIDR is greater than provided CIDR.
315
+ #Compare the sort order of the current CIDR with a provided CIDR and return:
316
+ #* 1 if the current CIDR is greater than the provided CIDR
317
+ #* 0 if the current CIDR and the provided CIDR are equal (base address and netmask are equal)
318
+ #* -1 if the current CIDR is less than the provided CIDR
319
+ #
320
+ # Example:
321
+ # cidr = NetAddr::CIDR.create('192.168.1.0/24')
322
+ # cidr <=> '192.168.2.0/24' => -1
323
+ # cidr <=> '192.168.0.0/24' => 1
324
+ # cidr <=> '192.168.1.0/24' => 0
314
325
  #
315
326
  #===Arguments:
316
327
  #* CIDR address or NetAddr::CIDR object
317
328
  #
318
329
  #===Returns:
319
- #* true or false
330
+ #* Integer
320
331
  #
321
- def >(cidr)
332
+ def <=>(cidr)
322
333
  if (!cidr.kind_of?(NetAddr::CIDR))
323
334
  begin
324
335
  cidr = NetAddr::CIDR.create(cidr)
@@ -334,19 +345,22 @@ private_class_method :new
334
345
  end
335
346
 
336
347
  # compare
337
- gt = false
338
- gt = true if ( NetAddr.cidr_gt_lt(self,cidr) == 1)
348
+ comparasin = NetAddr.cidr_gt_lt(self,cidr)
339
349
 
340
- return(gt)
350
+ return(comparasin)
341
351
  end
342
352
 
343
353
  #==============================================================================#
344
- # <()
354
+ # ==()
345
355
  #==============================================================================#
346
356
 
347
357
  #===Synopsis
348
358
  #Compare the sort order of the current CIDR with a provided CIDR and return true
349
- #if current CIDR is less than provided CIDR.
359
+ #if current CIDR is equal to the provided CIDR.
360
+ #
361
+ # Example:
362
+ # cidr = NetAddr::CIDR.create('192.168.1.0/24')
363
+ # cidr == '192.168.1.0/24' => true
350
364
  #
351
365
  #===Arguments:
352
366
  #* CIDR address or NetAddr::CIDR object
@@ -354,7 +368,7 @@ private_class_method :new
354
368
  #===Returns:
355
369
  #* true or false
356
370
  #
357
- def <(cidr)
371
+ def ==(cidr)
358
372
  if (!cidr.kind_of?(NetAddr::CIDR))
359
373
  begin
360
374
  cidr = NetAddr::CIDR.create(cidr)
@@ -370,19 +384,24 @@ private_class_method :new
370
384
  end
371
385
 
372
386
  # compare
373
- lt = false
374
- lt = true if ( NetAddr.cidr_gt_lt(self,cidr) == -1)
387
+ eq = false
388
+ eq = true if ( NetAddr.cidr_gt_lt(self,cidr) == 0)
375
389
 
376
- return(lt)
390
+ return(eq)
377
391
  end
392
+ alias :eql? :==
378
393
 
379
394
  #==============================================================================#
380
- # ==()
395
+ # >()
381
396
  #==============================================================================#
382
397
 
383
398
  #===Synopsis
384
399
  #Compare the sort order of the current CIDR with a provided CIDR and return true
385
- #if current CIDR is equal to the provided CIDR.
400
+ #if current CIDR is greater than provided CIDR.
401
+ #
402
+ # Example:
403
+ # cidr = NetAddr::CIDR.create('192.168.1.0/24')
404
+ # cidr > '192.168.0.0/24' => true
386
405
  #
387
406
  #===Arguments:
388
407
  #* CIDR address or NetAddr::CIDR object
@@ -390,7 +409,7 @@ private_class_method :new
390
409
  #===Returns:
391
410
  #* true or false
392
411
  #
393
- def ==(cidr)
412
+ def >(cidr)
394
413
  if (!cidr.kind_of?(NetAddr::CIDR))
395
414
  begin
396
415
  cidr = NetAddr::CIDR.create(cidr)
@@ -406,21 +425,156 @@ private_class_method :new
406
425
  end
407
426
 
408
427
  # compare
409
- eq = false
410
- eq = true if ( NetAddr.cidr_gt_lt(self,cidr) == 0)
428
+ gt = false
429
+ gt = true if ( NetAddr.cidr_gt_lt(self,cidr) == 1)
411
430
 
412
- return(eq)
431
+ return(gt)
432
+ end
433
+
434
+ #==============================================================================#
435
+ # []
436
+ #==============================================================================#
437
+
438
+ #===Synopsis
439
+ #Provide the IP at the given index of the CIDR.
440
+ #
441
+ # Example:
442
+ # cidr4 = NetAddr::CIDR.create('192.168.1.0/24')
443
+ # cidr4[1] => 192.168.1.1/32
444
+ #
445
+ #===Arguments:
446
+ #* index = Index number as an Integer
447
+ #
448
+ #===Returns:
449
+ #* NetAddr::CIDR object.
450
+ #
451
+ def [](index)
452
+ raise ArgumentError, "Integer expected for argument 'index' but " +
453
+ "#{index.class} provided." if (!index.kind_of?(Integer) )
454
+
455
+ addr = @network + index
456
+ if ( (@hostmask | addr) == (@hostmask | @network) )
457
+ addr = NetAddr.cidr_build(@version, addr)
458
+ else
459
+ raise BoundaryError, "Index of #{index} returns IP that is out of " +
460
+ "bounds of CIDR network."
461
+ end
462
+
463
+ return(addr)
464
+ end
465
+
466
+ #==============================================================================#
467
+ # allocate_rfc3531()
468
+ #==============================================================================#
469
+
470
+ #===Synopsis
471
+ #RFC 3531 describes a flexible method for IP subnet allocation from
472
+ #a larger parent network. Given the new netmask for subnet allocations from this CIDR,
473
+ #provide a list of those subnets arranged by the order in which they should be allocated.
474
+ #
475
+ # Example:
476
+ # cidr = NetAddr::CIDR.create('192.168.0.0/16')
477
+ # cidr.allocate_rfc3531(21, :Strategy => :centermost) => ["192.168.0.0/21"... "192.168.248.0/21"]
478
+ #
479
+ #===Arguments:
480
+ #* netmask (in bits) for all new subnet allocations
481
+ #* options = Hash with the following keys:
482
+ # :Objectify -- if true, return NetAddr::CIDR objects
483
+ # :Short -- if true, return IPv6 addresses in short-hand notation
484
+ # :Strategy -- allocation strategy to use. must be either :centermost or :leftmost (default)
485
+ #
486
+ #===Returns:
487
+ #* Array of Strings or CIDR objects
488
+ #
489
+ def allocate_rfc3531(netmask, options=nil)
490
+ short = false
491
+ objectify = false
492
+ strategy = :leftmost
493
+
494
+ # validate args
495
+ raise ArgumentError, "Expected Integer for argument (netmask), but #{max.class} received." if ( !netmask.kind_of?(Integer) )
496
+ raise BoundaryError, "Netmask (#{netmask}) is invalid for a version #{self.version} address." if (netmask > @address_len)
497
+ raise BoundaryError, "Netmask (#{netmask}) cannot be less than #{self.bits}." if (netmask < self.bits)
498
+ known_args = [:Objectify, :Short, :Strategy]
499
+ if (options)
500
+ if (!options.kind_of? Hash)
501
+ raise ArgumentError, "Expected Hash, but #{options.class} provided."
502
+ end
503
+ NetAddr.validate_args(options.keys,known_args)
504
+
505
+ if( options.has_key?(:Objectify) && options[:Objectify] == true )
506
+ objectify = true
507
+ end
508
+
509
+ if( options.has_key?(:Short) && options[:Short] == true )
510
+ short = true
511
+ end
512
+
513
+ if( options.has_key?(:Strategy))
514
+ strategy = options[:Strategy]
515
+ raise ArgumentError, "Argument :Strategy must be either :leftmost or :centermost." if (strategy != :leftmost && strategy != :centermost)
516
+ end
517
+ end
518
+
519
+ subnet_bits = netmask - self.bits
520
+ net_lshift = @address_len - netmask
521
+ new_mask = NetAddr.bits_to_mask(netmask,self.version)
522
+ cidr_list = []
523
+ if (strategy == :leftmost)
524
+ (0..(2**subnet_bits)-1).each do |num|
525
+ mirror = NetAddr.binary_mirror(num, subnet_bits)
526
+
527
+ if (!objectify)
528
+ my_ip_s = NetAddr.ip_int_to_str(@network | (mirror << net_lshift), @version)
529
+ my_ip_s = NetAddr.shorten(my_ip_s) if (short && @version == 6)
530
+ cidr_list.push( my_ip_s << '/' << netmask.to_s )
531
+ else
532
+ cidr_list.push( NetAddr.cidr_build(@version, @network | (mirror << net_lshift), new_mask ) )
533
+ end
534
+ end
535
+
536
+ else # :centermost
537
+ round = 1
538
+ bit_count = 1
539
+ lshift = subnet_bits/2
540
+ lshift -= 1 if (subnet_bits & 1 == 0) # if subnet_bits is even number
541
+
542
+ unique = {}
543
+ until (bit_count > subnet_bits)
544
+ (0..2**bit_count-1).each do |num|
545
+ shifted = num << lshift
546
+ if ( !unique.has_key?(shifted) )
547
+ if (!objectify)
548
+ my_ip_s = NetAddr.ip_int_to_str(@network | (shifted << net_lshift), @version)
549
+ my_ip_s = NetAddr.shorten(my_ip_s) if (short && @version == 6)
550
+ cidr_list.push( my_ip_s << '/' << netmask.to_s )
551
+ else
552
+ cidr_list.push( NetAddr.cidr_build(@version, @network | (shifted << net_lshift), new_mask ) )
553
+ end
554
+ unique[shifted] = true
555
+ end
556
+ end
557
+
558
+ lshift -= 1 if (round & 1 == 0) # if even round
559
+ round += 1
560
+ bit_count += 1
561
+ end
562
+ end
563
+
564
+ return(cidr_list)
413
565
  end
414
- alias :eql? :==
415
566
 
416
567
  #==============================================================================#
417
568
  # arpa()
418
569
  #==============================================================================#
419
570
 
420
571
  #===Synopsis
421
- #Depending on the IP version of the current CIDR,
572
+ #Depending on the IP version of the current CIDR,
422
573
  #return either an in-addr.arpa. or ip6.arpa. string. The netmask will be used
423
574
  #to determine the length of the returned string.
575
+ # Example:
576
+ # cidr = NetAddr::CIDR.create('192.168.1.1/24')
577
+ # cidr.arpa => "1.168.192.in-addr.arpa."
424
578
  #
425
579
  #===Arguments:
426
580
  #* none
@@ -476,6 +630,9 @@ private_class_method :new
476
630
 
477
631
  #===Synopsis
478
632
  #Provide number of bits in Netmask.
633
+ # Example:
634
+ # cidr = NetAddr::CIDR.create('192.168.1.1/24')
635
+ # cidr.bits => 24
479
636
  #
480
637
  #===Arguments:
481
638
  #* none
@@ -498,10 +655,12 @@ private_class_method :new
498
655
  #* -1 if the current CIDR is contained by (is subnet of) the provided CIDR
499
656
  #* nil if the two CIDR addresses are unrelated
500
657
  #
501
- # cidr4 = NetAddr::CIDR.create('192.168.1.0/24')
502
- # cidr4_2 = NetAddr::CIDR.create('192.168.1.0/26')
503
- # cidr4.cmp(cidr4_2)
504
- # cidr4.cmp('192.168.1.0/26')
658
+ # Example:
659
+ # cidr = NetAddr::CIDR.create('192.168.1.0/24')
660
+ # cidr.cmp('192.168.1.0/25') => 1
661
+ # cidr.cmp('192.168.1.0/24') => 0
662
+ # cidr.cmp('192.168.0.0/23') => -1
663
+ # cidr.cmp('10.0.0.0/24') => nil
505
664
  #
506
665
  #===Arguments:
507
666
  #* CIDR address or NetAddr::CIDR object
@@ -538,11 +697,12 @@ end
538
697
  #Determines if this CIDR contains (is supernet of)
539
698
  #the provided CIDR address or NetAddr::CIDR object.
540
699
  #
541
- # cidr4 = NetAddr::CIDR.create('192.168.1.1/24')
700
+ # Example:
701
+ # cidr4 = NetAddr::CIDR.create('192.168.1.0/24')
542
702
  # cidr6 = NetAddr::CIDR.create('fec0::/64')
543
703
  # cidr6_2 = NetAddr::CIDR.create('fec0::/96')
544
- # cidr4.contains?('192.168.1.2')
545
- # cidr6.contains?(cidr6_2)
704
+ # cidr4.contains?('192.168.1.2') => true
705
+ # cidr6.contains?(cidr6_2) => true
546
706
  #
547
707
  #===Arguments:
548
708
  #* cidr = CIDR address or NetAddr::CIDR object
@@ -579,11 +739,12 @@ end
579
739
  #===Synopsis
580
740
  #Returns network/netmask in CIDR format.
581
741
  #
742
+ # Example:
582
743
  # cidr4 = NetAddr::CIDR.create('192.168.1.1/24')
583
744
  # cidr6 = NetAddr::CIDR.create('fec0::/64')
584
- # cidr4.desc(:IP => true)
585
- # cidr4.desc()
586
- # cidr6.desc(:Short => true)
745
+ # cidr4.desc(:IP => true) => "192.168.1.1/24"
746
+ # cidr4.desc() => "192.168.1.0/24"
747
+ # cidr6.desc(:Short => true) => "fec0::/64"
587
748
  #
588
749
  #===Arguments:
589
750
  #* options = Optional hash with the following keys:
@@ -631,10 +792,11 @@ end
631
792
  #===Synopsis
632
793
  #Provide all IP addresses contained within the IP space of this CIDR.
633
794
  #
634
- # cidr4 = NetAddr::CIDR.create('192.168.1.1/24')
635
- # cidr6 = NetAddr::CIDR.create('fec0::/64')
636
- # cidr4.enumerate(:Limit => 4, :Bitstep => 32)
637
- # cidr6.enumerate(:Limit => 4, :Bitstep => 32, :Objectify => true)
795
+ # Example:
796
+ # cidr4 = NetAddr::CIDR.create('192.168.1.1/24')
797
+ # cidr6 = NetAddr::CIDR.create('fec0::/64')
798
+ # cidr4.enumerate(:Limit => 4, :Bitstep => 32)
799
+ # cidr6.enumerate(:Limit => 4, :Bitstep => 32, :Objectify => true)
638
800
  #
639
801
  #===Arguments:
640
802
  #* options = Hash with the following keys:
@@ -707,6 +869,7 @@ end
707
869
  #Given a list of subnets of the current CIDR, return a new list with any
708
870
  #holes (missing subnets) filled in.
709
871
  #
872
+ # Example:
710
873
  # cidr4 = NetAddr::CIDR.create('192.168.1.0/24')
711
874
  # cidr4.fill_in(['192.168.1.0/27','192.168.1.64/26','192.168.1.128/25'])
712
875
  #
@@ -784,6 +947,10 @@ end
784
947
  #===Synopsis
785
948
  #Provide original IP address passed during initialization.
786
949
  #
950
+ # Example:
951
+ # cidr = NetAddr::CIDR.create('192.168.1.1/24')
952
+ # cidr.ip => "192.168.1.1"
953
+ #
787
954
  #===Arguments:
788
955
  #* options = Hash with the following keys:
789
956
  # :Objectify -- if true, return NetAddr::CIDR object
@@ -832,6 +999,7 @@ end
832
999
  #Determines if this CIDR is contained within (is subnet of)
833
1000
  #the provided CIDR address or NetAddr::CIDR object.
834
1001
  #
1002
+ # Example:
835
1003
  # cidr4 = NetAddr::CIDR.create('192.168.1.1/24')
836
1004
  # cidr4.is_contained?('192.168.0.0/23')
837
1005
  #
@@ -858,9 +1026,9 @@ end
858
1026
  "with a version #{@version} CIDR."
859
1027
  end
860
1028
 
861
- network = cidr.packed_network
862
- netmask = cidr.packed_netmask
863
- hostmask = cidr.packed_hostmask
1029
+ network = cidr.to_i(:network)
1030
+ netmask = cidr.to_i(:netmask)
1031
+ hostmask = cidr.to_i(:hostmask)
864
1032
 
865
1033
  is_contained = true if ( NetAddr.cidr_compare(self,cidr) == -1 )
866
1034
 
@@ -874,6 +1042,10 @@ end
874
1042
  #===Synopsis
875
1043
  #Provide last IP address in this CIDR object.
876
1044
  #
1045
+ # Example:
1046
+ # cidr = NetAddr::CIDR.create('192.168.1.0/24')
1047
+ # cidr.last => "192.168.1.255"
1048
+ #
877
1049
  #===Arguments:
878
1050
  #* options = Hash with the following keys:
879
1051
  # :Objectify -- if true, return NetAddr::CIDR object
@@ -904,16 +1076,16 @@ end
904
1076
 
905
1077
  end
906
1078
 
907
- packed_ip = @network | @hostmask
1079
+ ip_int = @network | @hostmask
908
1080
  if (!objectify)
909
- ip = NetAddr.ip_int_to_str(packed_ip, @version)
1081
+ ip = NetAddr.ip_int_to_str(ip_int, @version)
910
1082
  ip = NetAddr.shorten(ip) if (short && !objectify && @version == 6)
911
1083
  else
912
- ip = NetAddr.cidr_build(@version,packed_ip)
1084
+ ip = NetAddr.cidr_build(@version,ip_int)
913
1085
  end
914
1086
 
915
1087
  return(ip)
916
- end
1088
+ end
917
1089
 
918
1090
  #==============================================================================#
919
1091
  # matches?()
@@ -924,6 +1096,7 @@ end
924
1096
  #if it falls within the range of addresses resulting from the combination of the
925
1097
  #IP and Wildcard Mask of this CIDR.
926
1098
  #
1099
+ # Example:
927
1100
  # cidr4 = NetAddr.CIDRv4.create('10.0.0.0', :WildcardMask => ['0.7.0.255', true])
928
1101
  # cidr4.matches?('10.0.0.22') -> true
929
1102
  # cidr4.matches?('10.8.0.1') -> false
@@ -937,19 +1110,19 @@ end
937
1110
  #* True or False
938
1111
  #
939
1112
  def matches?(ip)
940
- packed = nil
1113
+ ip_int = nil
941
1114
  if (!ip.kind_of?(NetAddr::CIDR))
942
1115
  begin
943
- packed = NetAddr.pack_ip_addr(ip, :Version => @version)
1116
+ ip_int = NetAddr.ip_to_i(ip, :Version => @version)
944
1117
  rescue NetAddr::ValidationError
945
1118
  raise NetAddr::ValidationError, "Provided IP must be a valid IPv#{@version} address."
946
1119
  end
947
1120
  else
948
1121
  raise NetAddr::ValidationError, "Provided CIDR must be of type #{self.class}" if (ip.class != self.class)
949
- packed = ip.packed_ip
1122
+ ip_int = ip.to_i(:ip)
950
1123
  end
951
1124
 
952
- return(true) if (@ip & @wildcard_mask == packed & @wildcard_mask)
1125
+ return(true) if (@ip & @wildcard_mask == ip_int & @wildcard_mask)
953
1126
  return(false)
954
1127
  end
955
1128
 
@@ -962,6 +1135,7 @@ end
962
1135
  #and ff00::/8 for IPv6), return its ethernet MAC address (EUI-48) mapping.
963
1136
  #MAC address is based on original IP address passed during initialization.
964
1137
  #
1138
+ # Example:
965
1139
  # mcast = NetAddr::CIDR.create('224.0.0.6')
966
1140
  # mcast.multicast_mac.address
967
1141
  #
@@ -1018,6 +1192,10 @@ end
1018
1192
  #===Synopsis
1019
1193
  #Provide netmask in CIDR format (/yy).
1020
1194
  #
1195
+ # Example:
1196
+ # cidr = NetAddr::CIDR.create('192.168.1.0/24')
1197
+ # cidr.netmask => "/24"
1198
+ #
1021
1199
  #===Arguments:
1022
1200
  #* none
1023
1201
  #
@@ -1036,6 +1214,10 @@ end
1036
1214
  #===Synopsis
1037
1215
  #Provide base network address.
1038
1216
  #
1217
+ # Example:
1218
+ # cidr = NetAddr::CIDR.create('192.168.1.0/24')
1219
+ # cidr.network => "192.168.1.0"
1220
+ #
1039
1221
  #===Arguments:
1040
1222
  #* options = Hash with the following fields:
1041
1223
  # :Objectify -- if true, return NetAddr::CIDR object
@@ -1086,6 +1268,7 @@ end
1086
1268
  #===Synopsis
1087
1269
  #Provide the next IP following the last available IP within this CIDR object.
1088
1270
  #
1271
+ # Example:
1089
1272
  # cidr4 = NetAddr::CIDR.create('192.168.1.1/24')
1090
1273
  # cidr6 = NetAddr::CIDR.create('fec0::/64')
1091
1274
  # cidr4.next_subnet()
@@ -1151,10 +1334,11 @@ end
1151
1334
  #Provide the next subnet following this CIDR object. The next subnet will
1152
1335
  #be of the same size as the current CIDR object.
1153
1336
  #
1154
- # cidr4 = NetAddr::CIDR.create('192.168.1.1/24')
1155
- # cidr6 = NetAddr::CIDR.create('fec0::/64')
1156
- # cidr4.next_subnet()
1157
- # cidr6.next_subnet(:Short => true)
1337
+ # Example:
1338
+ # cidr4 = NetAddr::CIDR.create('192.168.1.1/24')
1339
+ # cidr6 = NetAddr::CIDR.create('fec0::/64')
1340
+ # cidr4.next_subnet()
1341
+ # cidr6.next_subnet(:Short => true)
1158
1342
  #
1159
1343
  #===Arguments:
1160
1344
  #* options = Hash with the following keys:
@@ -1203,7 +1387,7 @@ end
1203
1387
  next_sub = NetAddr.shorten(next_sub) if (short && @version == 6)
1204
1388
  next_sub = next_sub << "/" << self.bits.to_s
1205
1389
  else
1206
- next_sub = NetAddr.cidr_build(@version,next_sub,self.packed_netmask)
1390
+ next_sub = NetAddr.cidr_build(@version,next_sub,self.to_i(:netmask))
1207
1391
  end
1208
1392
 
1209
1393
  return(next_sub)
@@ -1216,6 +1400,7 @@ end
1216
1400
  #===Synopsis
1217
1401
  #Provide the nth IP within this object.
1218
1402
  #
1403
+ # Example:
1219
1404
  # cidr4 = NetAddr::CIDR.create('192.168.1.1/24')
1220
1405
  # cidr4.nth(1)
1221
1406
  # cidr4.nth(1, :Objectify => true)
@@ -1270,100 +1455,16 @@ end
1270
1455
  return(my_ip)
1271
1456
  end
1272
1457
 
1273
- #==============================================================================#
1274
- # packed_hostmask()
1275
- #==============================================================================#
1276
-
1277
- #===Synopsis
1278
- #Provide an Integer representation of the Hostmask of this object.
1279
- #
1280
- #===Arguments:
1281
- #* none
1282
- #
1283
- #===Returns:
1284
- #* Integer
1285
- #
1286
- def packed_hostmask()
1287
- return(@hostmask)
1288
- end
1289
-
1290
- #==============================================================================#
1291
- # packed_ip()
1292
- #==============================================================================#
1293
-
1294
- #===Synopsis
1295
- #Provide an Integer representation of the IP address of this object.
1296
- #
1297
- #===Arguments:
1298
- #* none
1299
- #
1300
- #===Returns:
1301
- #* Integer
1302
- #
1303
- def packed_ip()
1304
- return(@ip)
1305
- end
1306
-
1307
- #==============================================================================#
1308
- # packed_netmask()
1309
- #==============================================================================#
1310
-
1311
- #===Synopsis
1312
- #Provide an Integer representation of the Netmask of this object.
1313
- #
1314
- #===Arguments:
1315
- #* none
1316
- #
1317
- #===Returns:
1318
- #* Integer
1319
- #
1320
- def packed_netmask()
1321
- return(@netmask)
1322
- end
1323
-
1324
- #==============================================================================#
1325
- # packed_network()
1326
- #==============================================================================#
1327
-
1328
- #===Synopsis
1329
- #Provide an Integer representation of the Network address of this object.
1330
- #
1331
- #===Arguments:
1332
- #* none
1333
- #
1334
- #===Returns:
1335
- #* Integer
1336
- #
1337
- def packed_network()
1338
- return(@network)
1339
- end
1340
-
1341
- #==============================================================================#
1342
- # packed_wildcard_mask()
1343
- #==============================================================================#
1344
-
1345
- #===Synopsis
1346
- #Provide an Integer representation of the IPv4 Wildcard Mask.
1347
- #
1348
- #===Arguments:
1349
- #* none
1350
- #
1351
- #===Returns:
1352
- #* Integer
1353
- #
1354
- def packed_wildcard_mask()
1355
- return(@wildcard_mask)
1356
- end
1357
-
1358
1458
  #==============================================================================#
1359
1459
  # range()
1360
1460
  #==============================================================================#
1361
1461
 
1362
1462
  #===Synopsis
1363
- #Given a set of index numbers for this CIDR, return all IP addresses within the
1463
+ #Given a set of index numbers for this CIDR, return all IP addresses within the
1364
1464
  #CIDR that are between them (inclusive). If an upper bound is not provided, then
1365
- #all addresses from the lower bound up will be returned.
1465
+ #all addresses from the lower bound up will be returned.
1366
1466
  #
1467
+ # Example:
1367
1468
  # cidr4 = NetAddr::CIDR.create('192.168.1.1/24')
1368
1469
  # cidr4.range(0, 1)
1369
1470
  # cidr4.range(0, 1, :Objectify => true)
@@ -1379,6 +1480,15 @@ end
1379
1480
  #
1380
1481
  #===Returns:
1381
1482
  #* Array of Strings, or Array of NetAddr::CIDR objects
1483
+ #
1484
+ #===Note:
1485
+ #If you do not need all of the fancy options in this method, then please consider
1486
+ #using the standard Ruby Range class as shown below.
1487
+ #
1488
+ # Example:
1489
+ # start = NetAddr::CIDR.create('192.168.1.0')
1490
+ # fin = NetAddr::CIDR.create('192.168.2.3')
1491
+ # (start..fin).each {|addr| puts addr.desc}
1382
1492
  #
1383
1493
  def range(lower, upper=nil, options=nil)
1384
1494
  known_args = [:Bitstep, :Objectify, :Short]
@@ -1511,12 +1621,12 @@ end
1511
1621
  # belongs in. take that half & repeat the process. every time
1512
1622
  # we repeat, store the non-matching half
1513
1623
  new_mask = self.bits + 1
1514
- lower_network = self.packed_network
1515
- upper_network = self.packed_network + 2**(@address_len - new_mask)
1624
+ lower_network = self.to_i(:network)
1625
+ upper_network = self.to_i(:network) + 2**(@address_len - new_mask)
1516
1626
 
1517
1627
  new_subnets = []
1518
1628
  until(new_mask > addr.bits)
1519
- if (addr.packed_network < upper_network)
1629
+ if (addr.to_i(:network) < upper_network)
1520
1630
  match = lower_network
1521
1631
  non_match = upper_network
1522
1632
  else
@@ -1548,6 +1658,7 @@ end
1548
1658
  #Resize the CIDR by changing the size of the Netmask.
1549
1659
  #Return the resulting CIDR as a new object.
1550
1660
  #
1661
+ # Example:
1551
1662
  # cidr4 = NetAddr::CIDR.create('192.168.1.1/24')
1552
1663
  # new_cidr = cidr4.resize(23)
1553
1664
  #
@@ -1577,6 +1688,7 @@ end
1577
1688
  #passed during initialization will be set to the base network address if
1578
1689
  #it no longer falls within the bounds of the CIDR.
1579
1690
  #
1691
+ # Example:
1580
1692
  # cidr4 = NetAddr::CIDR.create('192.168.1.1/24')
1581
1693
  # cidr4.resize!(23)
1582
1694
  #
@@ -1591,7 +1703,7 @@ end
1591
1703
  "#{bits.class} provided." if (!bits.kind_of?(Integer))
1592
1704
 
1593
1705
  NetAddr.validate_ip_netmask(bits, :Version => @version)
1594
- netmask = NetAddr.pack_ip_netmask(bits, :Version => @version)
1706
+ netmask = NetAddr.netmask_to_i(bits, :Version => @version)
1595
1707
 
1596
1708
  @netmask = netmask
1597
1709
  @network = @network & netmask
@@ -1613,6 +1725,7 @@ end
1613
1725
  #Set the wildcard mask. Wildcard masks are typically used for matching
1614
1726
  #entries in an access-list.
1615
1727
  #
1728
+ # Example:
1616
1729
  # cidr4 = NetAddr::CIDR.create('192.168.1.0/24')
1617
1730
  # cidr4.set_wildcard_mask('0.0.0.255', true)
1618
1731
  # cidr4.set_wildcard_mask('255.255.255.0')
@@ -1625,20 +1738,20 @@ end
1625
1738
  #* nil
1626
1739
  #
1627
1740
  def set_wildcard_mask(mask, bit_flipped=false)
1628
- packed = nil
1741
+ netmask_int = nil
1629
1742
  if (mask.kind_of?(Integer))
1630
1743
  NetAddr.validate_ip_int(mask,@version)
1631
- packed = mask
1744
+ netmask_int = mask
1632
1745
  else
1633
1746
  begin
1634
1747
  NetAddr.validate_ip_str(mask,@version)
1635
- packed = NetAddr.ip_str_to_int(mask, @version)
1748
+ netmask_int = NetAddr.ip_str_to_int(mask, @version)
1636
1749
  rescue NetAddr::ValidationError
1637
1750
  raise NetAddr::ValidationError, "Wildcard Mask must be a valid IPv#{@version} address."
1638
1751
  end
1639
1752
  end
1640
- packed = ~packed if (bit_flipped)
1641
- @wildcard_mask = packed
1753
+ netmask_int = ~netmask_int if (bit_flipped)
1754
+ @wildcard_mask = netmask_int
1642
1755
 
1643
1756
  return(nil)
1644
1757
  end
@@ -1650,6 +1763,10 @@ end
1650
1763
  #===Synopsis
1651
1764
  #Provide number of IP addresses within this CIDR.
1652
1765
  #
1766
+ # Example:
1767
+ # cidr = NetAddr::CIDR.create('192.168.1.0/24')
1768
+ # cidr.size => 256
1769
+ #
1653
1770
  #===Arguments:
1654
1771
  #* none
1655
1772
  #
@@ -1683,6 +1800,7 @@ end
1683
1800
  #If neither :Bits nor :IPCount is provided, then the current CIDR will be split in half.
1684
1801
  #If both :Bits and :IPCount are provided, then :Bits takes precedence.
1685
1802
  #
1803
+ # Example:
1686
1804
  # cidr4 = NetAddr::CIDR.create('192.168.1.0/24')
1687
1805
  # cidr6 = NetAddr::CIDR.create('fec0::/64')
1688
1806
  # cidr4.subnet(:Bits => 28, :NumSubnets => 3)
@@ -1703,7 +1821,7 @@ end
1703
1821
  #
1704
1822
  def subnet(options=nil)
1705
1823
  known_args = [:Bits, :IPCount, :NumSubnets, :Objectify, :Short]
1706
- my_network = self.packed_network
1824
+ my_network = self.to_i(:network)
1707
1825
  my_mask = self.bits
1708
1826
  subnet_bits = my_mask + 1
1709
1827
  min_count = nil
@@ -1785,7 +1903,7 @@ end
1785
1903
  new_subnets.push("#{subnet.network}/#{subnet_bits}")
1786
1904
  end
1787
1905
  else
1788
- new_subnets.push( NetAddr.cidr_build(@version, subnet.packed_network, NetAddr.bits_to_mask(subnet_bits,version) ) )
1906
+ new_subnets.push( NetAddr.cidr_build(@version, subnet.to_i(:network), NetAddr.bits_to_mask(subnet_bits,version) ) )
1789
1907
  end
1790
1908
  end
1791
1909
 
@@ -1810,6 +1928,73 @@ end
1810
1928
  return(new_subnets)
1811
1929
  end
1812
1930
 
1931
+ #==============================================================================#
1932
+ # succ()
1933
+ #==============================================================================#
1934
+
1935
+ #===Synopsis
1936
+ #Provide the next subnet following this CIDR object. The next subnet will
1937
+ #be of the same size as the current CIDR object.
1938
+ #
1939
+ # Example:
1940
+ # cidr = NetAddr::CIDR.create('192.168.1.0/24')
1941
+ # cidr.succ => 192.168.2.0/24
1942
+ #
1943
+ #===Arguments:
1944
+ #* none
1945
+ #
1946
+ #===Returns:
1947
+ #* NetAddr::CIDR object.
1948
+ #
1949
+ def succ()
1950
+ bitstep = 2**(@address_len - self.bits)
1951
+ next_sub = @network + bitstep
1952
+
1953
+ if (next_sub > @all_f)
1954
+ raise BoundaryError, "Returned subnet is out of bounds for IPv#{@version}."
1955
+ end
1956
+
1957
+ next_sub = NetAddr.cidr_build(@version,next_sub,self.to_i(:netmask))
1958
+
1959
+ return(next_sub)
1960
+ end
1961
+
1962
+ #==============================================================================#
1963
+ # to_i()
1964
+ #==============================================================================#
1965
+
1966
+ #===Synopsis
1967
+ #Convert the requested attribute of the CIDR to an Integer.
1968
+ # Example:
1969
+ # cidr = NetAddr::CIDR.create('192.168.1.1/24')
1970
+ # cidr.to_i => 3232235776
1971
+ # cidr.to_i(:hostmask) => 255
1972
+ # cidr.to_i(:ip) => 3232235777
1973
+ # cidr.to_i(:netmask) => 4294967040
1974
+ # cidr.to_i(:wildcard_mask) => 4294967040
1975
+ #
1976
+ #===Arguments:
1977
+ #* attribute -- attribute of the CIDR to convert to an Integer (:hostmask, :ip, :netmask, :network, or :wildcard_mask).
1978
+ #
1979
+ #===Returns:
1980
+ #* Integer
1981
+ #
1982
+ def to_i(attribute=:network)
1983
+ if(attribute == :network)
1984
+ return(@network)
1985
+ elsif(attribute == :hostmask)
1986
+ return(@hostmask)
1987
+ elsif(attribute == :ip)
1988
+ return(@ip)
1989
+ elsif(attribute == :netmask)
1990
+ return(@netmask)
1991
+ elsif(attribute == :wildcard_mask)
1992
+ return(@wildcard_mask)
1993
+ else
1994
+ raise ArgumentError, "Attribute is unrecognized. Must be :hostmask, :ip, :netmask, :network, or :wildcard_mask."
1995
+ end
1996
+ end
1997
+
1813
1998
  #==============================================================================#
1814
1999
  # wildcard_mask()
1815
2000
  #==============================================================================#
@@ -1817,6 +2002,11 @@ end
1817
2002
  #===Synopsis
1818
2003
  #Return the wildcard mask.
1819
2004
  #
2005
+ # Example:
2006
+ # cidr = NetAddr::CIDR.create('10.1.0.0/24', :WildcardMask => ['0.7.0.255', true])
2007
+ # cidr.wildcard_mask => "255.248.255.0"
2008
+ # cidr.wildcard_mask(true) => "0.7.0.255"
2009
+ #
1820
2010
  #===Arguments:
1821
2011
  #* bit_flipped = if set True then returned the bit-flipped version of the wildcard mask.
1822
2012
  #
@@ -1860,6 +2050,10 @@ class CIDRv4 < CIDR
1860
2050
  #===Synopsis
1861
2051
  #Provide IPv4 Hostmask in extended format (y.y.y.y).
1862
2052
  #
2053
+ # Example:
2054
+ # cidr = NetAddr::CIDR.create('10.1.0.0/24')
2055
+ # cidr.hostmask_ext => "0.0.0.255"
2056
+ #
1863
2057
  #===Arguments:
1864
2058
  #* none
1865
2059
  #
@@ -1877,6 +2071,10 @@ class CIDRv4 < CIDR
1877
2071
  #===Synopsis
1878
2072
  #Provide IPv4 netmask in extended format (y.y.y.y).
1879
2073
  #
2074
+ # Example:
2075
+ # cidr = NetAddr::CIDR.create('10.1.0.0/24')
2076
+ # cidr.netmask_ext => "255.255.255.0"
2077
+ #
1880
2078
  #===Arguments:
1881
2079
  #* none
1882
2080
  #
@@ -1900,6 +2098,80 @@ end # end class CIDRv4
1900
2098
  # Addresses of this class are composed of a 128-bit address space.
1901
2099
  class CIDRv6 < CIDR
1902
2100
  public_class_method :new
2101
+
2102
+ #==============================================================================#
2103
+ # unique_local()
2104
+ #==============================================================================#
2105
+
2106
+ #===Synopsis
2107
+ #Generate an IPv6 Unique Local CIDR address based on the algorithm described
2108
+ #in RFC 4193.
2109
+ #
2110
+ #From the RFC:
2111
+ #
2112
+ # 1) Obtain the current time of day in 64-bit NTP format [NTP].
2113
+ #
2114
+ # 2) Obtain an EUI-64 identifier from the system running this
2115
+ # algorithm. If an EUI-64 does not exist, one can be created from
2116
+ # a 48-bit MAC address as specified in [ADDARCH]. If an EUI-64
2117
+ # cannot be obtained or created, a suitably unique identifier,
2118
+ # local to the node, should be used (e.g., system serial number).
2119
+ #
2120
+ # 3) Concatenate the time of day with the system-specific identifier
2121
+ # in order to create a key.
2122
+ #
2123
+ # 4) Compute an SHA-1 digest on the key as specified in [FIPS, SHA1];
2124
+ # the resulting value is 160 bits.
2125
+ #
2126
+ # 5) Use the least significant 40 bits as the Global ID.
2127
+ #
2128
+ # 6) Concatenate FC00::/7, the L bit set to 1, and the 40-bit Global
2129
+ # ID to create a Local IPv6 address prefix.
2130
+ #
2131
+ # Example:
2132
+ # eui = NetAddr::EUI.create('aabb.ccdd.eeff')
2133
+ # NetAddr::CIDRv6.unique_local(eui) => fdb4:3014:e277:0000:0000:0000:0000:0000/48
2134
+ #
2135
+ #===Arguments:
2136
+ #* NetAddr::EUI object
2137
+ #
2138
+ #===Returns:
2139
+ #* CIDRv6 object
2140
+ #
2141
+ def CIDRv6.unique_local(eui)
2142
+
2143
+ if (eui.kind_of?(NetAddr::EUI48) )
2144
+ eui = eui.to_eui64.to_s
2145
+ elsif (eui.kind_of?(NetAddr::EUI64) )
2146
+ eui = eui.to_s
2147
+ else
2148
+ raise ArgumentError, "Expected NetAddr::EUI object but #{eui.class} received."
2149
+ end
2150
+
2151
+ ntp_time = ''
2152
+
2153
+ # get current time (32-bits), convert to 4-byte string, and append to ntp_time
2154
+ time = Time.now.to_i
2155
+ 4.times do
2156
+ ntp_time.insert(0, (time & 0xff).chr )
2157
+ time = time >> 8
2158
+ end
2159
+
2160
+ # create 32-bit fractional, convert to 4-byte string, and append to ntp_time
2161
+ fract = rand(2**32-1)
2162
+ 4.times do
2163
+ ntp_time.insert(0, (fract & 0xff).chr )
2164
+ fract = fract >> 8
2165
+ end
2166
+
2167
+ # create sha1 hash
2168
+ pre_hash = ntp_time << eui
2169
+ gid = Digest::SHA1.hexdigest(pre_hash).slice!(30..39)
2170
+ addr = 'fd' << gid << '00000000000000000000'
2171
+
2172
+ return( NetAddr::CIDRv6.new(addr.to_i(16), 0xffffffffffff00000000000000000000 ) )
2173
+ end
2174
+
1903
2175
  end # end class CIDRv6
1904
2176
 
1905
2177
  end # module NetAddr