netaddr 1.5.3 → 2.0.1

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/lib/cidr.rb DELETED
@@ -1,2014 +0,0 @@
1
- module NetAddr
2
-
3
- #=CIDR - Classless Inter-Domain Routing
4
- #
5
- #A class & series of methods for creating and manipulating CIDR network
6
- #addresses. Both IPv4 and IPv6 are supported.
7
- #
8
- #This class accepts a CIDR address, via the CIDR.create method,
9
- #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.
10
- #CIDR.create then creates either a CIDRv4 or CIDRv6 object. An optional tag hash may be
11
- #provided with each CIDR as a way of adding custom labels.
12
- #
13
- #Upon initialization, the IP version is auto-detected and assigned to the
14
- #CIDR. The original IP/Netmask passed within the CIDR is stored and then
15
- #used to determine the confines of the CIDR block. Various properties of the
16
- #CIDR block are accessible via several different methods. There are also
17
- #methods for modifying the CIDR or creating new derivative CIDR's.
18
- #
19
- #An example CIDR object is as follows:
20
- # NetAddr::CIDR.create('192.168.1.20/24')
21
- #
22
- #This would create a CIDR object (192.168.1.0/24) with the following properties:
23
- # version = 4
24
- # base network = 192.168.1.0
25
- # ip address = 192.168.1.20
26
- # netmask = /24 (255.255.255.0)
27
- # size = 256 IP addresses
28
- # broadcast = 192.168.1.255
29
- #
30
- #You can see how the CIDR object is based around the entire IP space
31
- #defined by the provided IP/Netmask pair, and not necessarily the individual
32
- #IP address itself.
33
- #
34
- class CIDR
35
-
36
- private_class_method :new
37
-
38
-
39
- # IP version 4 or 6.
40
- attr_reader :version
41
-
42
- # Hash of custom tags. Should be in the format tag => value.
43
- attr_reader :tag
44
-
45
- # Integer of either 32 or 128 bits in length, with all bits set to 1
46
- attr_reader :all_f
47
-
48
- # Integer representing number of bits in this CIDR address
49
- attr_reader :address_len
50
-
51
- # Hash of custom tags. Should be in the format tag => value.
52
- #
53
- # Example:
54
- # cidr4.tag[:name] = 'IPv4 CIDR'
55
- # puts cidr4.tag[:name]
56
- #
57
- def tag=(new_tag)
58
- if (!new_tag.kind_of? Hash)
59
- raise ArgumentError, "Expected Hash, but #{new_tag.class} provided."
60
- end
61
- @tag = new_tag
62
- end
63
-
64
- #===Synopsis
65
- #Create a new CIDRv4 or CIDRv6 object.
66
- #CIDR formatted netmasks take precedence over extended formatted ones.
67
- #CIDR address defaults to a host network (/32 or /128) if netmask not provided.
68
- #:Mask takes precedence over netmask given within CIDR addresses.
69
- #Version will be auto-detected if not specified.
70
- #
71
- # NetAddr::CIDR.create('192.168.1.1/24')
72
- # NetAddr::CIDR.create('192.168.1.1 255.255.255.0')
73
- # NetAddr::CIDR.create(0x0a010001,:Mask => 0xffffff00:Version => 4)
74
- # NetAddr::CIDR.create('192.168.1.1',:WildcardMask => ['0.7.0.255', true])
75
- # NetAddr::CIDR.create('192.168.1.1',:WildcardMask => [0x000007ff, true]
76
- # NetAddr::CIDR.create('192.168.5.0',:WildcardMask => ['255.248.255.0'])
77
- # NetAddr::CIDR.create('fec0::/64')
78
- # NetAddr::CIDR.create('fec0::/64',:Tag => {'interface' => 'g0/1'})
79
- # NetAddr::CIDR.create('::ffff:192.168.1.1/96')
80
- #
81
- #===Arguments:
82
- #* addr = CIDR address as a String, or an IP address as an Integer
83
- #* options = Hash with the following keys:
84
- # :Mask -- Integer representing a binary IP Netmask
85
- # :Version -- IP version - Integer
86
- # :Tag -- Custom descriptor tag - Hash, tag => value.
87
- # :WildcardMask -- 2 element Array. First element contains a special bit mask used for
88
- # advanced IP pattern matching. The second element should be set to True if this
89
- # bit mask is bit flipped.
90
- #
91
- def CIDR.create(addr, options=nil)
92
- known_args = [:Mask, :Version, :Tag, :WildcardMask]
93
- ip, netmask, tag = nil, nil, {}
94
- version, wildcard_mask ,wildcard_mask_bit_flipped = nil, nil, false
95
- netmask_int, all_f = nil, nil
96
-
97
- # validate options
98
- if (options)
99
- raise ArgumentError, "Hash expected for argument 'options' but " +
100
- "#{options.class} provided." if (!options.kind_of?(Hash) )
101
- NetAddr.validate_args(options.keys,known_args)
102
-
103
- if (options.has_key?(:Mask))
104
- netmask_int = options[:Mask]
105
- raise ArgumentError, "Expected Integer, but #{netmask_int.class} " +
106
- "provided for option :Mask." if (!netmask_int.kind_of?(Integer))
107
- end
108
-
109
- if (options.has_key?(:Tag))
110
- tag = options[:Tag]
111
- if (!tag.kind_of? Hash)
112
- raise ArgumentError, "Expected Hash, but #{tag.class} provided for option :Tag."
113
- end
114
- end
115
-
116
- if (options.has_key?(:Version))
117
- version = options[:Version]
118
- if (version != 4 && version != 6)
119
- raise VersionError, ":Version should be 4 or 6, but was '#{version}'."
120
- end
121
- end
122
-
123
- if (options.has_key?(:WildcardMask))
124
- if (!options[:WildcardMask].kind_of?(Array))
125
- raise ArgumentError, "Expected Array, but #{options[:WildcardMask].class} provided for option :WildcardMask."
126
- end
127
-
128
- wildcard_mask = options[:WildcardMask][0]
129
- if (!wildcard_mask.kind_of?(String) && !wildcard_mask.kind_of?(Integer))
130
- raise ArgumentError, "Expected String or Integer, but #{wildcard_mask.class} provided for wildcard mask."
131
- end
132
- wildcard_mask_bit_flipped = true if (options[:WildcardMask][1] && options[:WildcardMask][1].kind_of?(TrueClass))
133
- end
134
- end
135
-
136
- # validate addr arg & set version if not provided by user
137
- if (addr.kind_of?(String))
138
- version = NetAddr.detect_ip_version(addr) if (!version)
139
-
140
- # if extended netmask provided. should only apply to ipv4
141
- if (version == 4 && addr =~ /.+\s+.+/ )
142
- addr,netmask = addr.split(' ')
143
- end
144
-
145
- # if netmask part of ip, then separate ip & mask.
146
- if (addr =~ /\//)
147
- ip,netmask = addr.split(/\//)
148
- if (!ip || !netmask)
149
- raise ArgumentError, "CIDR address is improperly formatted. Missing netmask after '/' character."
150
- end
151
- else
152
- ip = addr
153
- end
154
-
155
- NetAddr.validate_ip_str(ip,version)
156
- ip = NetAddr.ip_str_to_int(ip,version)
157
-
158
- elsif (addr.kind_of?(Integer))
159
- ip = addr
160
- if (!version)
161
- if (ip < 2**32)
162
- version = 4
163
- else
164
- version = 6
165
- end
166
- end
167
- NetAddr.validate_ip_int(ip,version)
168
-
169
- else
170
- raise ArgumentError, "String or Integer expected for argument 'addr' but #{addr.class} provided."
171
- end
172
-
173
- # set all_f based on version
174
- all_f = 2**32-1
175
- all_f = 2**128-1 if (version == 6)
176
-
177
- # set netmask. netmask_int takes precedence. set to all_f if no netmask provided
178
- if (netmask_int)
179
- NetAddr.validate_netmask_int(netmask_int,version,true)
180
- netmask = netmask_int
181
- elsif (netmask)
182
- NetAddr.validate_netmask_str(netmask,version)
183
- netmask = NetAddr.netmask_str_to_int(netmask, version)
184
- else
185
- netmask = all_f
186
- end
187
-
188
- # set wildcard mask if not provided, or validate if provided.
189
- if (wildcard_mask)
190
- begin
191
- if (wildcard_mask.kind_of?(String))
192
- NetAddr.validate_ip_str(wildcard_mask,version)
193
- wildcard_mask = NetAddr.ip_str_to_int(wildcard_mask, version)
194
- else (wildcard_mask.kind_of?(Integer))
195
- NetAddr.validate_ip_int(wildcard_mask,version)
196
- end
197
- rescue Exception => error
198
- raise ValidationError, "Provided wildcard mask failed validation: #{error}"
199
- end
200
- end
201
-
202
- return( NetAddr.cidr_build(version, ip, netmask, tag, wildcard_mask, wildcard_mask_bit_flipped) )
203
- end
204
-
205
- # This method performs absolutely no error checking, and is meant to be used only by
206
- # other internal methods for the sake of the speedier creation of CIDR objects.
207
- # Please consider using #create unless you know what you are doing with 100% certainty.
208
- #
209
- #===Arguments:
210
- #* ip - Integer representing an ip address
211
- #* netmask - Integer representing a binary netmask
212
- #* tag - Hash used to append custom tags to CIDR
213
- #* wildcard_mask - Integer representing a binary mask
214
- #* wildcard_mask_bit_flipped - indicates whether or not the wildcard_mask is bit-flipped or not
215
- #
216
- def initialize(ip, netmask=nil, tag={}, wildcard_mask=nil, wildcard_mask_bit_flipped=false)
217
- @ip = ip
218
-
219
- if ( self.kind_of?(NetAddr::CIDRv4) )
220
- @version = 4
221
- @address_len = 32
222
- else
223
- @version = 6
224
- @address_len = 128
225
- end
226
- @all_f = 2**@address_len - 1
227
-
228
- if (netmask)
229
- @netmask = netmask
230
- else
231
- @netmask = 2**@address_len - 1
232
- end
233
-
234
- @network = (@ip & @netmask)
235
- @hostmask = @netmask ^ @all_f
236
- @tag = tag
237
-
238
- if (!wildcard_mask)
239
- @wildcard_mask = @netmask
240
- else
241
- @wildcard_mask = wildcard_mask
242
- @wildcard_mask = ~@wildcard_mask if (wildcard_mask_bit_flipped)
243
- end
244
-
245
- end
246
-
247
- #===Synopsis
248
- #Compare the sort order of the current CIDR with a provided CIDR and return true
249
- #if current CIDR is less than provided CIDR.
250
- #
251
- # Example:
252
- # cidr = NetAddr::CIDR.create('192.168.1.0/24')
253
- # cidr < '192.168.2.0/24' => true
254
- #
255
- #===Arguments:
256
- #* CIDR address or NetAddr::CIDR object
257
- #
258
- #===Returns:
259
- #* true or false
260
- #
261
- def <(cidr)
262
- if (!cidr.kind_of?(NetAddr::CIDR))
263
- begin
264
- cidr = NetAddr::CIDR.create(cidr)
265
- rescue Exception => error
266
- raise ArgumentError, "Provided argument raised the following " +
267
- "errors: #{error}"
268
- end
269
- end
270
-
271
- if (cidr.version != @version)
272
- raise VersionError, "Attempted to compare a version #{cidr.version} CIDR " +
273
- "with a version #{@version} CIDR."
274
- end
275
-
276
- # compare
277
- lt = false
278
- lt = true if ( NetAddr.cidr_gt_lt(self,cidr) == -1)
279
-
280
- return(lt)
281
- end
282
-
283
- #===Synopsis
284
- #Compare the sort order of the current CIDR with a provided CIDR and return:
285
- #* 1 if the current CIDR is greater than the provided CIDR
286
- #* 0 if the current CIDR and the provided CIDR are equal (base address and netmask are equal)
287
- #* -1 if the current CIDR is less than the provided CIDR
288
- #
289
- # Example:
290
- # cidr = NetAddr::CIDR.create('192.168.1.0/24')
291
- # cidr <=> '192.168.2.0/24' => -1
292
- # cidr <=> '192.168.0.0/24' => 1
293
- # cidr <=> '192.168.1.0/24' => 0
294
- #
295
- #===Arguments:
296
- #* CIDR address or NetAddr::CIDR object
297
- #
298
- #===Returns:
299
- #* Integer
300
- #
301
- def <=>(cidr)
302
- if (!cidr.kind_of?(NetAddr::CIDR))
303
- begin
304
- cidr = NetAddr::CIDR.create(cidr)
305
- rescue Exception => error
306
- raise ArgumentError, "Provided argument raised the following " +
307
- "errors: #{error}"
308
- end
309
- end
310
-
311
- if (cidr.version != @version)
312
- raise VersionError, "Attempted to compare a version #{cidr.version} CIDR " +
313
- "with a version #{@version} CIDR."
314
- end
315
-
316
- # compare
317
- comparasin = NetAddr.cidr_gt_lt(self,cidr)
318
-
319
- return(comparasin)
320
- end
321
-
322
- #===Synopsis
323
- #Compare the sort order of the current CIDR with a provided CIDR and return true
324
- #if current CIDR is equal to the provided CIDR.
325
- #
326
- # Example:
327
- # cidr = NetAddr::CIDR.create('192.168.1.0/24')
328
- # cidr == '192.168.1.0/24' => true
329
- #
330
- #===Arguments:
331
- #* CIDR address or NetAddr::CIDR object
332
- #
333
- #===Returns:
334
- #* true or false
335
- #
336
- def ==(cidr)
337
- if (!cidr.kind_of?(NetAddr::CIDR))
338
- begin
339
- cidr = NetAddr::CIDR.create(cidr)
340
- rescue Exception => error
341
- raise ArgumentError, "Provided argument raised the following " +
342
- "errors: #{error}"
343
- end
344
- end
345
-
346
- if (cidr.version != @version)
347
- raise VersionError, "Attempted to compare a version #{cidr.version} CIDR " +
348
- "with a version #{@version} CIDR."
349
- end
350
-
351
- # compare
352
- eq = false
353
- eq = true if ( NetAddr.cidr_gt_lt(self,cidr) == 0)
354
-
355
- return(eq)
356
- end
357
- alias :eql? :==
358
-
359
- #===Synopsis
360
- #Compare the sort order of the current CIDR with a provided CIDR and return true
361
- #if current CIDR is greater than provided CIDR.
362
- #
363
- # Example:
364
- # cidr = NetAddr::CIDR.create('192.168.1.0/24')
365
- # cidr > '192.168.0.0/24' => true
366
- #
367
- #===Arguments:
368
- #* CIDR address or NetAddr::CIDR object
369
- #
370
- #===Returns:
371
- #* true or false
372
- #
373
- def >(cidr)
374
- if (!cidr.kind_of?(NetAddr::CIDR))
375
- begin
376
- cidr = NetAddr::CIDR.create(cidr)
377
- rescue Exception => error
378
- raise ArgumentError, "Provided argument raised the following " +
379
- "errors: #{error}"
380
- end
381
- end
382
-
383
- if (cidr.version != @version)
384
- raise VersionError, "Attempted to compare a version #{cidr.version} CIDR " +
385
- "with a version #{@version} CIDR."
386
- end
387
-
388
- # compare
389
- gt = false
390
- gt = true if ( NetAddr.cidr_gt_lt(self,cidr) == 1)
391
-
392
- return(gt)
393
- end
394
-
395
- #===Synopsis
396
- #Provide the IP at the given index of the CIDR.
397
- #
398
- # Example:
399
- # cidr4 = NetAddr::CIDR.create('192.168.1.0/24')
400
- # cidr4[1] => 192.168.1.1/32
401
- #
402
- #===Arguments:
403
- #* index = Index number as an Integer
404
- #
405
- #===Returns:
406
- #* NetAddr::CIDR object.
407
- #
408
- def [](index)
409
- raise ArgumentError, "Integer expected for argument 'index' but " +
410
- "#{index.class} provided." if (!index.kind_of?(Integer) )
411
-
412
- addr = @network + index
413
- if ( (@hostmask | addr) == (@hostmask | @network) )
414
- addr = NetAddr.cidr_build(@version, addr)
415
- else
416
- raise BoundaryError, "Index of #{index} returns IP that is out of " +
417
- "bounds of CIDR network."
418
- end
419
-
420
- return(addr)
421
- end
422
-
423
- #===Synopsis
424
- #RFC 3531 describes a flexible method for IP subnet allocation from
425
- #a larger parent network. Given the new netmask for subnet allocations from this CIDR,
426
- #provide a list of those subnets arranged by the order in which they should be allocated.
427
- #
428
- # Example:
429
- # cidr = NetAddr::CIDR.create('192.168.0.0/16')
430
- # cidr.allocate_rfc3531(21, :Strategy => :centermost) => ["192.168.0.0/21"... "192.168.248.0/21"]
431
- #
432
- #===Arguments:
433
- #* netmask (in bits) for all new subnet allocations
434
- #* options = Hash with the following keys:
435
- # :Objectify -- if true, return NetAddr::CIDR objects
436
- # :Short -- if true, return IPv6 addresses in short-hand notation
437
- # :Strategy -- allocation strategy to use. must be either :centermost or :leftmost (default)
438
- #
439
- #===Returns:
440
- #* Array of Strings or CIDR objects
441
- #
442
- def allocate_rfc3531(netmask, options=nil)
443
- short = false
444
- objectify = false
445
- strategy = :leftmost
446
-
447
- # validate args
448
- raise ArgumentError, "Expected Integer for argument (netmask), but #{max.class} received." if ( !netmask.kind_of?(Integer) )
449
- raise BoundaryError, "Netmask (#{netmask}) is invalid for a version #{self.version} address." if (netmask > @address_len)
450
- raise BoundaryError, "Netmask (#{netmask}) cannot be less than #{self.bits}." if (netmask < self.bits)
451
- known_args = [:Objectify, :Short, :Strategy]
452
- if (options)
453
- if (!options.kind_of? Hash)
454
- raise ArgumentError, "Expected Hash, but #{options.class} provided."
455
- end
456
- NetAddr.validate_args(options.keys,known_args)
457
-
458
- if( options.has_key?(:Objectify) && options[:Objectify] == true )
459
- objectify = true
460
- end
461
-
462
- if( options.has_key?(:Short) && options[:Short] == true )
463
- short = true
464
- end
465
-
466
- if( options.has_key?(:Strategy))
467
- strategy = options[:Strategy]
468
- raise ArgumentError, "Argument :Strategy must be either :leftmost or :centermost." if (strategy != :leftmost && strategy != :centermost)
469
- end
470
- end
471
-
472
- subnet_bits = netmask - self.bits
473
- net_lshift = @address_len - netmask
474
- new_mask = NetAddr.bits_to_mask(netmask,self.version)
475
- cidr_list = []
476
- if (strategy == :leftmost)
477
- (0..(2**subnet_bits)-1).each do |num|
478
- mirror = NetAddr.binary_mirror(num, subnet_bits)
479
-
480
- if (!objectify)
481
- my_ip_s = NetAddr.ip_int_to_str(@network | (mirror << net_lshift), @version)
482
- my_ip_s = NetAddr.shorten(my_ip_s) if (short && @version == 6)
483
- cidr_list.push( my_ip_s << '/' << netmask.to_s )
484
- else
485
- cidr_list.push( NetAddr.cidr_build(@version, @network | (mirror << net_lshift), new_mask ) )
486
- end
487
- end
488
-
489
- else # :centermost
490
- round = 1
491
- bit_count = 1
492
- lshift = subnet_bits/2
493
- lshift -= 1 if (subnet_bits & 1 == 0) # if subnet_bits is even number
494
-
495
- unique = {}
496
- until (bit_count > subnet_bits)
497
- (0..2**bit_count-1).each do |num|
498
- shifted = num << lshift
499
- if ( !unique.has_key?(shifted) )
500
- if (!objectify)
501
- my_ip_s = NetAddr.ip_int_to_str(@network | (shifted << net_lshift), @version)
502
- my_ip_s = NetAddr.shorten(my_ip_s) if (short && @version == 6)
503
- cidr_list.push( my_ip_s << '/' << netmask.to_s )
504
- else
505
- cidr_list.push( NetAddr.cidr_build(@version, @network | (shifted << net_lshift), new_mask ) )
506
- end
507
- unique[shifted] = true
508
- end
509
- end
510
-
511
- lshift -= 1 if (round & 1 == 0) # if even round
512
- round += 1
513
- bit_count += 1
514
- end
515
- end
516
-
517
- return(cidr_list)
518
- end
519
-
520
- #===Synopsis
521
- #Depending on the IP version of the current CIDR,
522
- #return either an in-addr.arpa. or ip6.arpa. string. The netmask will be used
523
- #to determine the length of the returned string.
524
- # Example:
525
- # cidr = NetAddr::CIDR.create('192.168.1.1/24')
526
- # cidr.arpa => "1.168.192.in-addr.arpa."
527
- #
528
- #===Arguments:
529
- #* none
530
- #
531
- #===Returns:
532
- #* String
533
- #
534
- def arpa()
535
-
536
- base = self.ip()
537
- netmask = self.bits()
538
-
539
- if (@version == 4)
540
- net = base.split('.')
541
-
542
- if (netmask)
543
- while (netmask < 32)
544
- net.pop
545
- netmask = netmask + 8
546
- end
547
- end
548
-
549
- arpa = net.reverse.join('.')
550
- arpa << ".in-addr.arpa."
551
-
552
- elsif (@version == 6)
553
- fields = base.split(':')
554
- net = []
555
- fields.each do |field|
556
- (field.split("")).each do |x|
557
- net.push(x)
558
- end
559
- end
560
-
561
- if (netmask)
562
- while (netmask < 128)
563
- net.pop
564
- netmask = netmask + 4
565
- end
566
- end
567
-
568
- arpa = net.reverse.join('.')
569
- arpa << ".ip6.arpa."
570
-
571
- end
572
-
573
- return(arpa)
574
- end
575
-
576
- #===Synopsis
577
- #Provide number of bits in Netmask.
578
- # Example:
579
- # cidr = NetAddr::CIDR.create('192.168.1.1/24')
580
- # cidr.bits => 24
581
- #
582
- #===Arguments:
583
- #* none
584
- #
585
- #===Returns:
586
- #* Integer.
587
- #
588
- def bits()
589
- return(NetAddr.mask_to_bits(@netmask))
590
- end
591
-
592
- #===Synopsis
593
- #Compare the current CIDR with a provided CIDR and return:
594
- #* 1 if the current CIDR contains (is supernet of) the provided CIDR
595
- #* 0 if the current CIDR and the provided CIDR are equal (base address and netmask are equal)
596
- #* -1 if the current CIDR is contained by (is subnet of) the provided CIDR
597
- #* nil if the two CIDR addresses are unrelated
598
- #
599
- # Example:
600
- # cidr = NetAddr::CIDR.create('192.168.1.0/24')
601
- # cidr.cmp('192.168.1.0/25') => 1
602
- # cidr.cmp('192.168.1.0/24') => 0
603
- # cidr.cmp('192.168.0.0/23') => -1
604
- # cidr.cmp('10.0.0.0/24') => nil
605
- #
606
- #===Arguments:
607
- #* CIDR address or NetAddr::CIDR object
608
- #
609
- #===Returns:
610
- #* Integer or nil
611
- #
612
- def cmp(cidr)
613
- if (!cidr.kind_of?(NetAddr::CIDR))
614
- begin
615
- cidr = NetAddr::CIDR.create(cidr)
616
- rescue Exception => error
617
- raise ArgumentError, "Provided argument raised the following " +
618
- "errors: #{error}"
619
- end
620
- end
621
-
622
- if (cidr.version != @version)
623
- raise VersionError, "Attempted to compare a version #{cidr.version} CIDR " +
624
- "with a version #{@version} CIDR."
625
- end
626
-
627
- # compare
628
- comparasin = NetAddr.cidr_compare(self,cidr)
629
-
630
- return(comparasin)
631
- end
632
-
633
- #===Synopsis
634
- #Determines if this CIDR contains (is supernet of)
635
- #the provided CIDR address or NetAddr::CIDR object.
636
- #
637
- # Example:
638
- # cidr4 = NetAddr::CIDR.create('192.168.1.0/24')
639
- # cidr6 = NetAddr::CIDR.create('fec0::/64')
640
- # cidr6_2 = NetAddr::CIDR.create('fec0::/96')
641
- # cidr4.contains?('192.168.1.2') => true
642
- # cidr6.contains?(cidr6_2) => true
643
- #
644
- #===Arguments:
645
- #* cidr = CIDR address or NetAddr::CIDR object
646
- #
647
- #===Returns:
648
- #* true or false
649
- #
650
- def contains?(cidr)
651
- contains = false
652
-
653
- if (!cidr.kind_of?(NetAddr::CIDR))
654
- begin
655
- cidr = NetAddr::CIDR.create(cidr)
656
- rescue Exception => error
657
- raise ArgumentError, "Provided argument raised the following " +
658
- "errors: #{error}"
659
- end
660
- end
661
-
662
- if (cidr.version != @version)
663
- raise VersionError, "Attempted to compare a version #{cidr.version} CIDR " +
664
- "with a version #{@version} CIDR."
665
- end
666
-
667
- contains = true if ( NetAddr.cidr_compare(self,cidr) == 1 )
668
-
669
- return(contains)
670
- end
671
-
672
- #===Synopsis
673
- #See to_s
674
- #
675
- def desc(options=nil)
676
- to_s(options)
677
- end
678
-
679
- #===Synopsis
680
- #Provide all IP addresses contained within the IP space of this CIDR.
681
- #
682
- # Example:
683
- # cidr4 = NetAddr::CIDR.create('192.168.1.1/24')
684
- # cidr6 = NetAddr::CIDR.create('fec0::/64')
685
- # cidr4.enumerate(:Limit => 4, :Bitstep => 32)
686
- # cidr6.enumerate(:Limit => 4, :Bitstep => 32, :Objectify => true)
687
- #
688
- #===Arguments:
689
- #* options = Hash with the following keys:
690
- # :Bitstep -- enumerate in X sized steps - Integer
691
- # :Limit -- limit returned list to X number of items - Integer
692
- # :Objectify -- if true, return NetAddr::CIDR objects
693
- # :Short -- if true, return IPv6 addresses in short-hand notation
694
- #
695
- #===Returns:
696
- #* Array of Strings, or Array of NetAddr::CIDR objects
697
- #
698
- def enumerate(options=nil)
699
- known_args = [:Bitstep, :Limit, :Objectify, :Short]
700
- bitstep = 1
701
- objectify = false
702
- limit = nil
703
- short = false
704
-
705
- if (options)
706
- if (!options.kind_of? Hash)
707
- raise ArgumentError, "Expected Hash, but #{options.class} provided."
708
- end
709
- NetAddr.validate_args(options.keys,known_args)
710
-
711
- if( options.has_key?(:Bitstep) )
712
- bitstep = options[:Bitstep]
713
- end
714
-
715
- if( options.has_key?(:Objectify) && options[:Objectify] == true )
716
- objectify = true
717
- end
718
-
719
- if( options.has_key?(:Limit) )
720
- limit = options[:Limit]
721
- end
722
-
723
- if( options.has_key?(:Short) && options[:Short] == true )
724
- short = true
725
- end
726
- end
727
-
728
- list = []
729
- my_ip = @network
730
- change_mask = @hostmask | my_ip
731
-
732
- until ( change_mask != (@hostmask | @network) )
733
- if (!objectify)
734
- my_ip_s = NetAddr.ip_int_to_str(my_ip, @version)
735
- my_ip_s = NetAddr.shorten(my_ip_s) if (short && @version == 6)
736
- list.push( my_ip_s )
737
- else
738
- list.push( NetAddr.cidr_build(@version,my_ip) )
739
- end
740
- my_ip = my_ip + bitstep
741
- change_mask = @hostmask | my_ip
742
- if (limit)
743
- limit = limit - 1
744
- break if (limit == 0)
745
- end
746
- end
747
-
748
- return(list)
749
- end
750
-
751
- #===Synopsis
752
- #Given a list of subnets of the current CIDR, return a new list with any
753
- #holes (missing subnets) filled in.
754
- #
755
- # Example:
756
- # cidr4 = NetAddr::CIDR.create('192.168.1.0/24')
757
- # cidr4.fill_in(['192.168.1.0/27','192.168.1.64/26','192.168.1.128/25'])
758
- #
759
- #===Arguments:
760
- #* list = Array of CIDR addresses, or Array of NetAddr::CIDR objects
761
- #* options = Hash with the following keys:
762
- # :Objectify -- if true, return NetAddr::CIDR objects
763
- # :Short -- if true, return IPv6 addresses in short-hand notation
764
- #
765
- #===Returns:
766
- #* Array of CIDR Strings, or an Array of NetAddr::CIDR objects
767
- #
768
-
769
- def fill_in(list, options=nil)
770
- known_args = [:Objectify, :Short]
771
- short = false
772
- objectify = false
773
-
774
- # validate list
775
- raise ArgumentError, "Array expected for argument 'list' but #{list.class} provided." if (!list.kind_of?(Array) )
776
-
777
- # validate options
778
- if (options)
779
- raise ArgumentError, "Hash expected for argument 'options' but " +
780
- "#{options.class} provided." if (!options.kind_of?(Hash) )
781
- NetAddr.validate_args(options.keys,known_args)
782
-
783
- if (options.has_key?(:Short) && options[:Short] == true)
784
- short = true
785
- end
786
-
787
- if (options.has_key?(:Objectify) && options[:Objectify] == true)
788
- objectify = true
789
- end
790
- end
791
-
792
- # validate each cidr and store in cidr_list
793
- cidr_list = []
794
- list.each do |obj|
795
- if (!obj.kind_of?(NetAddr::CIDR))
796
- begin
797
- obj = NetAddr::CIDR.create(obj)
798
- rescue Exception => error
799
- aise ArgumentError, "A provided CIDR raised the following " +
800
- "errors: #{error}"
801
- end
802
- end
803
-
804
- if (!obj.version == self.version)
805
- raise VersionError, "#{obj.desc(:Short => true)} is not a version #{self.version} address."
806
- end
807
-
808
- # make sure we contain the cidr
809
- if ( self.contains?(obj) == false )
810
- raise "#{obj.desc(:Short => true)} does not fit " +
811
- "within the bounds of #{self.desc(:Short => true)}."
812
- end
813
- cidr_list.push(obj)
814
- end
815
-
816
- complete_list = NetAddr.cidr_fill_in(self,cidr_list)
817
- if (!objectify)
818
- subnets = []
819
- complete_list.each {|entry| subnets.push(entry.desc(:Short => short))}
820
- return(subnets)
821
- else
822
- return(complete_list)
823
- end
824
- end
825
-
826
- #===Synopsis
827
- #Provide original IP address passed during initialization.
828
- #
829
- # Example:
830
- # cidr = NetAddr::CIDR.create('192.168.1.1/24')
831
- # cidr.ip => "192.168.1.1"
832
- #
833
- #===Arguments:
834
- #* options = Hash with the following keys:
835
- # :Objectify -- if true, return NetAddr::CIDR object
836
- # :Short -- if true, return IPv6 addresses in short-hand notation
837
- #
838
- #===Returns:
839
- #* String or NetAddr::CIDR object.
840
- #
841
- def ip(options=nil)
842
- known_args = [:Objectify, :Short]
843
- objectify = false
844
- short = false
845
-
846
- if (options)
847
- if (!options.kind_of?(Hash))
848
- raise ArgumentError, "Expected Hash, but " +
849
- "#{options.class} provided."
850
- end
851
- NetAddr.validate_args(options.keys,known_args)
852
-
853
- if( options.has_key?(:Short) && options[:Short] == true )
854
- short = true
855
- end
856
-
857
- if( options.has_key?(:Objectify) && options[:Objectify] == true )
858
- objectify = true
859
- end
860
- end
861
-
862
-
863
- if (!objectify)
864
- ip = NetAddr.ip_int_to_str(@ip, @version)
865
- ip = NetAddr.shorten(ip) if (short && @version == 6)
866
- else
867
- ip = NetAddr.cidr_build(@version,@ip)
868
- end
869
-
870
- return(ip)
871
- end
872
-
873
- #===Synopsis
874
- #Determines if this CIDR is contained within (is subnet of)
875
- #the provided CIDR address or NetAddr::CIDR object.
876
- #
877
- # Example:
878
- # cidr4 = NetAddr::CIDR.create('192.168.1.1/24')
879
- # cidr4.is_contained?('192.168.0.0/23')
880
- #
881
- #===Arguments:
882
- #* cidr = CIDR address or NetAddr::CIDR object
883
- #
884
- #===Returns:
885
- #* true or false
886
- #
887
- def is_contained?(cidr)
888
- is_contained = false
889
-
890
- if (!cidr.kind_of?(NetAddr::CIDR))
891
- begin
892
- cidr = NetAddr::CIDR.create(cidr)
893
- rescue Exception => error
894
- raise ArgumentError, "Provided argument raised the following " +
895
- "errors: #{error}"
896
- end
897
- end
898
-
899
- if (cidr.version != @version)
900
- raise VersionError, "Attempted to compare a version #{cidr.version} CIDR " +
901
- "with a version #{@version} CIDR."
902
- end
903
-
904
- network = cidr.to_i(:network)
905
- netmask = cidr.to_i(:netmask)
906
- hostmask = cidr.to_i(:hostmask)
907
-
908
- is_contained = true if ( NetAddr.cidr_compare(self,cidr) == -1 )
909
-
910
- return(is_contained)
911
- end
912
-
913
- #===Synopsis
914
- #Provide last IP address in this CIDR object.
915
- #
916
- # Example:
917
- # cidr = NetAddr::CIDR.create('192.168.1.0/24')
918
- # cidr.last => "192.168.1.255"
919
- #
920
- #===Arguments:
921
- #* options = Hash with the following keys:
922
- # :Objectify -- if true, return NetAddr::CIDR object
923
- # :Short -- if true, return IPv6 addresses in short-hand notation
924
- #
925
- #===Returns:
926
- #* String or NetAddr::CIDR object.
927
- #
928
- def last(options=nil)
929
- known_args = [:Objectify, :Short]
930
- objectify = false
931
- short = false
932
-
933
- if (options)
934
- if (!options.kind_of?(Hash))
935
- raise ArgumentError, "Expected Hash, but " +
936
- "#{options.class} provided."
937
- end
938
- NetAddr.validate_args(options.keys,known_args)
939
-
940
- if( options.has_key?(:Short) && options[:Short] == true )
941
- short = true
942
- end
943
-
944
- if( options.has_key?(:Objectify) && options[:Objectify] == true )
945
- objectify = true
946
- end
947
-
948
- end
949
-
950
- ip_int = @network | @hostmask
951
- if (!objectify)
952
- ip = NetAddr.ip_int_to_str(ip_int, @version)
953
- ip = NetAddr.shorten(ip) if (short && !objectify && @version == 6)
954
- else
955
- ip = NetAddr.cidr_build(@version,ip_int)
956
- end
957
-
958
- return(ip)
959
- end
960
-
961
- #===Synopsis
962
- #Given an IP address (or if a NetAddr::CIDR object, then the original IP of that object), determine
963
- #if it falls within the range of addresses resulting from the combination of the
964
- #IP and Wildcard Mask of this CIDR.
965
- #
966
- # Example:
967
- # cidr4 = NetAddr.CIDRv4.create('10.0.0.0', :WildcardMask => ['0.7.0.255', true])
968
- # cidr4.matches?('10.0.0.22') -> true
969
- # cidr4.matches?('10.8.0.1') -> false
970
- # cidr4.matches?('10.1.0.1') -> true
971
- # cidr4.matches?('10.0.1.22') -> false
972
- #
973
- #===Arguments:
974
- #* ip = IP address as a String or a CIDR object
975
- #
976
- #===Returns:
977
- #* True or False
978
- #
979
- def matches?(ip)
980
- ip_int = nil
981
- if (!ip.kind_of?(NetAddr::CIDR))
982
- begin
983
- ip_int = NetAddr.ip_to_i(ip, :Version => @version)
984
- rescue NetAddr::ValidationError
985
- raise NetAddr::ValidationError, "Provided IP must be a valid IPv#{@version} address."
986
- end
987
- else
988
- raise NetAddr::ValidationError, "Provided CIDR must be of type #{self.class}" if (ip.class != self.class)
989
- ip_int = ip.to_i(:ip)
990
- end
991
-
992
- return(true) if (@ip & @wildcard_mask == ip_int & @wildcard_mask)
993
- return(false)
994
- end
995
-
996
- #===Synopsis
997
- #Assuming this CIDR is a valid multicast address (224.0.0.0/4 for IPv4
998
- #and ff00::/8 for IPv6), return its ethernet MAC address (EUI-48) mapping.
999
- #MAC address is based on original IP address passed during initialization.
1000
- #
1001
- # Example:
1002
- # mcast = NetAddr::CIDR.create('224.0.0.6')
1003
- # mcast.multicast_mac.address
1004
- #
1005
- #===Arguments:
1006
- #* options = Hash with the following keys:
1007
- # :Objectify -- if true, return EUI objects
1008
- #
1009
- #===Returns:
1010
- #* String or NetAddr::EUI48 object
1011
- #
1012
- def multicast_mac(options=nil)
1013
- known_args = [:Objectify]
1014
- objectify = false
1015
-
1016
- if (options)
1017
- if (!options.kind_of? Hash)
1018
- raise ArgumentError, "Expected Hash, but #{options.class} provided."
1019
- end
1020
- NetAddr.validate_args(options.keys,known_args)
1021
-
1022
- if (options.has_key?(:Objectify) && options[:Objectify] == true)
1023
- objectify = true
1024
- end
1025
- end
1026
-
1027
- if (@version == 4)
1028
- if (@ip & 0xf0000000 == 0xe0000000)
1029
- # map low order 23-bits of ip to 01:00:5e:00:00:00
1030
- mac = @ip & 0x007fffff | 0x01005e000000
1031
- else
1032
- raise ValidationError, "#{self.ip} is not a valid multicast address. IPv4 multicast " +
1033
- "addresses should be in the range 224.0.0.0/4."
1034
- end
1035
- else
1036
- if (@ip & (0xff << 120) == 0xff << 120)
1037
- # map low order 32-bits of ip to 33:33:00:00:00:00
1038
- mac = @ip & (2**32-1) | 0x333300000000
1039
- else
1040
- raise ValidationError, "#{self.ip} is not a valid multicast address. IPv6 multicast " +
1041
- "addresses should be in the range ff00::/8."
1042
- end
1043
- end
1044
-
1045
- eui = NetAddr::EUI48.new(mac)
1046
- eui = eui.address if (!objectify)
1047
-
1048
- return(eui)
1049
- end
1050
-
1051
- #===Synopsis
1052
- #Provide netmask in CIDR format (/yy).
1053
- #
1054
- # Example:
1055
- # cidr = NetAddr::CIDR.create('192.168.1.0/24')
1056
- # cidr.netmask => "/24"
1057
- #
1058
- #===Arguments:
1059
- #* none
1060
- #
1061
- #===Returns:
1062
- #* String
1063
- #
1064
- def netmask()
1065
- bits = NetAddr.mask_to_bits(@netmask)
1066
- return("/#{bits}")
1067
- end
1068
-
1069
- #===Synopsis
1070
- #Provide base network address.
1071
- #
1072
- # Example:
1073
- # cidr = NetAddr::CIDR.create('192.168.1.0/24')
1074
- # cidr.network => "192.168.1.0"
1075
- #
1076
- #===Arguments:
1077
- #* options = Hash with the following fields:
1078
- # :Objectify -- if true, return NetAddr::CIDR object
1079
- # :Short -- if true, return IPv6 addresses in short-hand notation
1080
- #
1081
- #===Returns:
1082
- #* String or NetAddr::CIDR object.
1083
- #
1084
- def network(options=nil)
1085
- known_args = [:Objectify, :Short]
1086
- objectify = false
1087
- short = false
1088
-
1089
- if (options)
1090
- if (!options.kind_of?(Hash))
1091
- raise ArgumentError, "Expected Hash, but " +
1092
- "#{options.class} provided."
1093
- end
1094
- NetAddr.validate_args(options.keys,known_args)
1095
-
1096
- if( options.has_key?(:Short) && options[:Short] == true )
1097
- short = true
1098
- end
1099
-
1100
- if( options.has_key?(:Objectify) && options[:Objectify] == true )
1101
- objectify = true
1102
- end
1103
- end
1104
-
1105
-
1106
- if (!objectify)
1107
- ip = NetAddr.ip_int_to_str(@network, @version)
1108
- ip = NetAddr.shorten(ip) if (short && @version == 6)
1109
- else
1110
- ip = NetAddr.cidr_build(@version,@network)
1111
- end
1112
-
1113
- return(ip)
1114
- end
1115
-
1116
- alias :base :network
1117
- alias :first :network
1118
-
1119
- #===Synopsis
1120
- #Provide the next IP following the last available IP within this CIDR object.
1121
- #
1122
- # Example:
1123
- # cidr4 = NetAddr::CIDR.create('192.168.1.1/24')
1124
- # cidr6 = NetAddr::CIDR.create('fec0::/64')
1125
- # cidr4.next_subnet()
1126
- # cidr6.next_subnet(:Short => true)}
1127
- #
1128
- #===Arguments:
1129
- #* options = Hash with the following keys:
1130
- # :Bitstep -- step in X sized steps - Integer
1131
- # :Objectify -- if true, return NetAddr::CIDR object
1132
- # :Short -- if true, return IPv6 addresses in short-hand notation
1133
- #
1134
- #===Returns:
1135
- #* String or NetAddr::CIDR object.
1136
- #
1137
- def next_ip(options=nil)
1138
- known_args = [:Bitstep, :Objectify, :Short]
1139
- bitstep = 1
1140
- objectify = false
1141
- short = false
1142
-
1143
- if (options)
1144
- if (!options.kind_of?(Hash))
1145
- raise ArgumentError, "Expected Hash, but " +
1146
- "#{options.class} provided."
1147
- end
1148
- NetAddr.validate_args(options.keys,known_args)
1149
-
1150
- if( options.has_key?(:Bitstep) )
1151
- bitstep = options[:Bitstep]
1152
- end
1153
-
1154
- if( options.has_key?(:Short) && options[:Short] == true )
1155
- short = true
1156
- end
1157
-
1158
- if( options.has_key?(:Objectify) && options[:Objectify] == true )
1159
- objectify = true
1160
- end
1161
- end
1162
-
1163
- next_ip = @network + @hostmask + bitstep
1164
-
1165
- if (next_ip > @all_f)
1166
- raise BoundaryError, "Returned IP is out of bounds for IPv#{@version}."
1167
- end
1168
-
1169
-
1170
- if (!objectify)
1171
- next_ip = NetAddr.ip_int_to_str(next_ip, @version)
1172
- next_ip = NetAddr.shorten(next_ip) if (short && @version == 6)
1173
- else
1174
- next_ip = NetAddr.cidr_build(@version,next_ip)
1175
- end
1176
-
1177
- return(next_ip)
1178
- end
1179
-
1180
- #===Synopsis
1181
- #Provide the next subnet following this CIDR object. The next subnet will
1182
- #be of the same size as the current CIDR object.
1183
- #
1184
- # Example:
1185
- # cidr4 = NetAddr::CIDR.create('192.168.1.1/24')
1186
- # cidr6 = NetAddr::CIDR.create('fec0::/64')
1187
- # cidr4.next_subnet()
1188
- # cidr6.next_subnet(:Short => true)
1189
- #
1190
- #===Arguments:
1191
- #* options = Hash with the following keys:
1192
- # :Bitstep -- step in X sized steps. - Integer
1193
- # :Objectify -- if true, return NetAddr::CIDR object
1194
- # :Short -- if true, return IPv6 addresses in short-hand notation
1195
- #
1196
- #===Returns:
1197
- #* String or NetAddr::CIDR object.
1198
- #
1199
- def next_subnet(options=nil)
1200
- known_args = [:Bitstep, :Objectify, :Short]
1201
- bitstep = 1
1202
- objectify = false
1203
- short = false
1204
-
1205
- if (options)
1206
- if (!options.kind_of?(Hash))
1207
- raise ArgumentError, "Expected Hash, but " +
1208
- "#{options.class} provided."
1209
- end
1210
- NetAddr.validate_args(options.keys,known_args)
1211
-
1212
- if( options.has_key?(:Bitstep) )
1213
- bitstep = options[:Bitstep]
1214
- end
1215
-
1216
- if( options.has_key?(:Short) && options[:Short] == true )
1217
- short = true
1218
- end
1219
-
1220
- if( options.has_key?(:Objectify) && options[:Objectify] == true )
1221
- objectify = true
1222
- end
1223
- end
1224
-
1225
- bitstep = bitstep * (2**(@address_len - self.bits) )
1226
- next_sub = @network + bitstep
1227
-
1228
- if (next_sub > @all_f)
1229
- raise BoundaryError, "Returned subnet is out of bounds for IPv#{@version}."
1230
- end
1231
-
1232
- if (!objectify)
1233
- next_sub = NetAddr.ip_int_to_str(next_sub, @version)
1234
- next_sub = NetAddr.shorten(next_sub) if (short && @version == 6)
1235
- next_sub = next_sub << "/" << self.bits.to_s
1236
- else
1237
- next_sub = NetAddr.cidr_build(@version,next_sub,self.to_i(:netmask))
1238
- end
1239
-
1240
- return(next_sub)
1241
- end
1242
-
1243
- #===Synopsis
1244
- #Provide the nth IP within this object.
1245
- #
1246
- # Example:
1247
- # cidr4 = NetAddr::CIDR.create('192.168.1.1/24')
1248
- # cidr4.nth(1)
1249
- # cidr4.nth(1, :Objectify => true)
1250
- #
1251
- #===Arguments:
1252
- #* index = Index number as an Integer
1253
- #* options = Hash with the following keys:
1254
- # :Objectify -- if true, return NetAddr::CIDR objects
1255
- # :Short -- if true, return IPv6 addresses in short-hand notation
1256
- #
1257
- #===Returns:
1258
- #* String or NetAddr::CIDR object.
1259
- #
1260
- def nth(index, options=nil)
1261
- known_args = [:Objectify, :Short]
1262
- objectify = false
1263
- short = false
1264
-
1265
- # validate list
1266
- raise ArgumentError, "Integer expected for argument 'index' but " +
1267
- "#{index.class} provided." if (!index.kind_of?(Integer) )
1268
-
1269
- # validate options
1270
- if (options)
1271
- raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash) )
1272
- NetAddr.validate_args(options.keys,known_args)
1273
-
1274
- if( options.has_key?(:Short) && options[:Short] == true )
1275
- short = true
1276
- end
1277
-
1278
- if( options.has_key?(:Objectify) && options[:Objectify] == true )
1279
- objectify = true
1280
- end
1281
- end
1282
-
1283
- my_ip = @network + index
1284
- if ( (@hostmask | my_ip) == (@hostmask | @network) )
1285
-
1286
- if (!objectify)
1287
- my_ip = NetAddr.ip_int_to_str(my_ip, @version)
1288
- my_ip = NetAddr.shorten(my_ip) if (short && @version == 6)
1289
- else
1290
- my_ip = NetAddr.cidr_build(@version,my_ip)
1291
- end
1292
-
1293
- else
1294
- raise BoundaryError, "Index of #{index} returns IP that is out of " +
1295
- "bounds of CIDR network."
1296
- end
1297
-
1298
- return(my_ip)
1299
- end
1300
-
1301
- #===Synopsis
1302
- #Given a set of index numbers for this CIDR, return all IP addresses within the
1303
- #CIDR that are between them (inclusive). If an upper bound is not provided, then
1304
- #all addresses from the lower bound up will be returned.
1305
- #
1306
- # Example:
1307
- # cidr4 = NetAddr::CIDR.create('192.168.1.1/24')
1308
- # cidr4.range(0, 1)
1309
- # cidr4.range(0, 1, :Objectify => true)
1310
- # cidr4.range(0, nil, :Objectify => true)
1311
- #
1312
- #===Arguments:
1313
- #* lower = Lower range boundary index as an Integer
1314
- #* upper = Upper range boundary index as an Integer
1315
- #* options = Hash with the following keys:
1316
- # :Bitstep -- enumerate in X sized steps - Integer
1317
- # :Objectify -- if true, return NetAddr::CIDR objects
1318
- # :Short -- if true, return IPv6 addresses in short-hand notation
1319
- #
1320
- #===Returns:
1321
- #* Array of Strings, or Array of NetAddr::CIDR objects
1322
- #
1323
- #===Note:
1324
- #If you do not need all of the fancy options in this method, then please consider
1325
- #using the standard Ruby Range class as shown below.
1326
- #
1327
- # Example:
1328
- # start = NetAddr::CIDR.create('192.168.1.0')
1329
- # fin = NetAddr::CIDR.create('192.168.2.3')
1330
- # (start..fin).each {|addr| puts addr.desc}
1331
- #
1332
- def range(lower, upper=nil, options=nil)
1333
- known_args = [:Bitstep, :Objectify, :Short]
1334
- objectify = false
1335
- short = false
1336
- bitstep = 1
1337
-
1338
- # validate indexes
1339
- raise ArgumentError, "Integer expected for argument 'lower' " +
1340
- "but #{lower.class} provided." if (!lower.kind_of?(Integer))
1341
-
1342
- raise ArgumentError, "Integer expected for argument 'upper' " +
1343
- "but #{upper.class} provided." if (upper && !upper.kind_of?(Integer))
1344
-
1345
- upper = @hostmask if (upper.nil?)
1346
- indexes = [lower,upper]
1347
- indexes.sort!
1348
- if ( (indexes[0] < 0) || (indexes[0] > self.size) )
1349
- raise BoundaryError, "Index #{indexes[0]} is out of bounds for this CIDR."
1350
- end
1351
-
1352
- if (indexes[1] >= self.size)
1353
- raise BoundaryError, "Index #{indexes[1]} is out of bounds for this CIDR."
1354
- end
1355
-
1356
- # validate options
1357
- if (options)
1358
- raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash) )
1359
- NetAddr.validate_args(options.keys,known_args)
1360
-
1361
- if( options.has_key?(:Short) && options[:Short] == true )
1362
- short = true
1363
- end
1364
-
1365
- if( options.has_key?(:Objectify) && options[:Objectify] == true )
1366
- objectify = true
1367
- end
1368
-
1369
- if( options.has_key?(:Bitstep) )
1370
- bitstep = options[:Bitstep]
1371
- end
1372
- end
1373
-
1374
- # make range
1375
- start_ip = @network + indexes[0]
1376
- end_ip = @network + indexes[1]
1377
- my_ip = start_ip
1378
- list = []
1379
- until (my_ip > end_ip)
1380
- if (!objectify)
1381
- ip = NetAddr.ip_int_to_str(my_ip, @version)
1382
- ip = NetAddr.shorten(ip) if (short && @version == 6)
1383
- else
1384
- ip = NetAddr.cidr_build(@version,my_ip)
1385
- end
1386
-
1387
- list.push(ip)
1388
- my_ip += bitstep
1389
- end
1390
-
1391
- return(list)
1392
- end
1393
-
1394
- #===Synopsis
1395
- #Given a single subnet of the current CIDR, provide the remainder of
1396
- #the subnets. For example if the original CIDR is 192.168.0.0/24 and you
1397
- #provide 192.168.0.64/26 as the portion to exclude, then 192.168.0.0/26,
1398
- #and 192.168.0.128/25 will be returned as the remainders.
1399
- #
1400
- # cidr4 = NetAddr::CIDR.create('192.168.1.0/24')
1401
- # cidr4.remainder('192.168.1.32/27')
1402
- # cidr4.remainder('192.168.1.32/27', :Objectify => true)
1403
- #
1404
- #===Arguments:
1405
- #* addr = CIDR address or NetAddr::CIDR object
1406
- #* options = Hash with the following keys:
1407
- # :Objectify -- if true, return NetAddr::CIDR objects
1408
- # :Short -- if true, return IPv6 addresses in short-hand notation
1409
- #
1410
- #===Returns:
1411
- #* Array of Strings, or Array of NetAddr::CIDR objects
1412
- #
1413
- def remainder(addr, options=nil)
1414
- known_args = [:Objectify, :Short]
1415
- short = nil
1416
- objectify = nil
1417
-
1418
- # validate options
1419
- if (options)
1420
- raise ArgumentError, "Hash expected for argument 'options' but " +
1421
- "#{options.class} provided." if (!options.kind_of?(Hash) )
1422
- NetAddr.validate_args(options.keys,known_args)
1423
-
1424
- if( options.has_key?(:Short) && options[:Short] == true )
1425
- short = true
1426
- end
1427
-
1428
- if( options.has_key?(:Objectify) && options[:Objectify] == true )
1429
- objectify = true
1430
- end
1431
- end
1432
-
1433
- if ( !addr.kind_of?(NetAddr::CIDR) )
1434
- begin
1435
- addr = NetAddr::CIDR.create(addr)
1436
- rescue Exception => error
1437
- raise ArgumentError, "Argument 'addr' raised the following " +
1438
- "errors: #{error}"
1439
- end
1440
- end
1441
-
1442
-
1443
- # make sure 'addr' is the same ip version
1444
- if ( addr.version != @version )
1445
- raise VersionError, "#{addr.desc(:Short => true)} is of a different " +
1446
- "IP version than #{self.desc(:Short => true)}."
1447
- end
1448
-
1449
- # make sure we contain 'to_exclude'
1450
- if ( self.contains?(addr) != true )
1451
- raise BoundaryError, "#{addr.desc(:Short => true)} does not fit " +
1452
- "within the bounds of #{self.desc(:Short => true)}."
1453
- end
1454
-
1455
- # split this cidr in half & see which half 'to_exclude'
1456
- # belongs in. take that half & repeat the process. every time
1457
- # we repeat, store the non-matching half
1458
- new_mask = self.bits + 1
1459
- lower_network = self.to_i(:network)
1460
- upper_network = self.to_i(:network) + 2**(@address_len - new_mask)
1461
-
1462
- new_subnets = []
1463
- until(new_mask > addr.bits)
1464
- if (addr.to_i(:network) < upper_network)
1465
- match = lower_network
1466
- non_match = upper_network
1467
- else
1468
- match = upper_network
1469
- non_match = lower_network
1470
- end
1471
-
1472
- if (!objectify)
1473
- non_match = NetAddr.ip_int_to_str(non_match, @version)
1474
- non_match = NetAddr.shorten(non_match) if (short && @version == 6)
1475
- new_subnets.unshift("#{non_match}/#{new_mask}")
1476
- else
1477
- new_subnets.unshift( NetAddr.cidr_build(@version, non_match, NetAddr.bits_to_mask(new_mask,version) ) )
1478
- end
1479
-
1480
- new_mask = new_mask + 1
1481
- lower_network = match
1482
- upper_network = match + 2**(@address_len - new_mask)
1483
- end
1484
-
1485
- return(new_subnets)
1486
- end
1487
-
1488
- #===Synopsis
1489
- #Resize the CIDR by changing the size of the Netmask.
1490
- #Return the resulting CIDR as a new object.
1491
- #
1492
- # Example:
1493
- # cidr4 = NetAddr::CIDR.create('192.168.1.1/24')
1494
- # new_cidr = cidr4.resize(23)
1495
- #
1496
- #===Arguments:
1497
- #* bits = Netmask as an Integer
1498
- #
1499
- #===Returns:
1500
- #* NetAddr::CIDR object
1501
- #
1502
- def resize(bits)
1503
- raise ArgumentError, "Integer or Hash expected, but " +
1504
- "#{bits.class} provided." if (!bits.kind_of?(Integer))
1505
-
1506
- NetAddr.validate_ip_netmask(bits, :Version => @version)
1507
- netmask = NetAddr.bits_to_mask(bits, @version)
1508
- network = @network & netmask
1509
-
1510
- return( NetAddr.cidr_build(@version, network, netmask) )
1511
- end
1512
-
1513
- #===Synopsis
1514
- #Resize the current CIDR by changing the size of the Netmask. The original IP
1515
- #passed during initialization will be set to the base network address if
1516
- #it no longer falls within the bounds of the CIDR.
1517
- #
1518
- # Example:
1519
- # cidr4 = NetAddr::CIDR.create('192.168.1.1/24')
1520
- # cidr4.resize!(23)
1521
- #
1522
- #===Arguments:
1523
- #* bits = Netmask as an Integer
1524
- #
1525
- #===Returns:
1526
- #* True
1527
- #
1528
- def resize!(bits)
1529
- raise ArgumentError, "Integer or Hash expected, but " +
1530
- "#{bits.class} provided." if (!bits.kind_of?(Integer))
1531
-
1532
- NetAddr.validate_ip_netmask(bits, :Version => @version)
1533
- netmask = NetAddr.netmask_to_i(bits, :Version => @version)
1534
-
1535
- @netmask = netmask
1536
- @network = @network & netmask
1537
- @hostmask = @netmask ^ @all_f
1538
-
1539
- # check @ip
1540
- if ((@ip & @netmask) != (@network))
1541
- @ip = @network
1542
- end
1543
-
1544
- return(true)
1545
- end
1546
-
1547
- #===Synopsis
1548
- #Set the wildcard mask. Wildcard masks are typically used for matching
1549
- #entries in an access-list.
1550
- #
1551
- # Example:
1552
- # cidr4 = NetAddr::CIDR.create('192.168.1.0/24')
1553
- # cidr4.set_wildcard_mask('0.0.0.255', true)
1554
- # cidr4.set_wildcard_mask('255.255.255.0')
1555
- #
1556
- #===Arguments:
1557
- #* mask = wildcard mask as a String or Integer
1558
- #* bit_flipped = if set True then the wildcard mask is interpereted as bit-flipped.
1559
- #
1560
- #===Returns:
1561
- #* nil
1562
- #
1563
- def set_wildcard_mask(mask, bit_flipped=false)
1564
- netmask_int = nil
1565
- if (mask.kind_of?(Integer))
1566
- NetAddr.validate_ip_int(mask,@version)
1567
- netmask_int = mask
1568
- else
1569
- begin
1570
- NetAddr.validate_ip_str(mask,@version)
1571
- netmask_int = NetAddr.ip_str_to_int(mask, @version)
1572
- rescue NetAddr::ValidationError
1573
- raise NetAddr::ValidationError, "Wildcard Mask must be a valid IPv#{@version} address."
1574
- end
1575
- end
1576
- netmask_int = ~netmask_int if (bit_flipped)
1577
- @wildcard_mask = netmask_int
1578
-
1579
- return(nil)
1580
- end
1581
-
1582
- #===Synopsis
1583
- #Provide number of IP addresses within this CIDR.
1584
- #
1585
- # Example:
1586
- # cidr = NetAddr::CIDR.create('192.168.1.0/24')
1587
- # cidr.size => 256
1588
- #
1589
- #===Arguments:
1590
- #* none
1591
- #
1592
- #===Returns:
1593
- #* Integer
1594
- #
1595
- def size()
1596
- return(@hostmask + 1)
1597
- end
1598
-
1599
- #===Synopsis
1600
- #Create subnets for this CIDR. There are 2 ways to create subnets:
1601
- # * By providing the netmask (in bits) of the new subnets with :Bits.
1602
- # * By providing the number of IP addresses needed in the new subnets with :IPCount
1603
- #
1604
- #:NumSubnets is used to determine how the CIDR is subnetted. For example, if I request
1605
- #the following operation:
1606
- #
1607
- # NetAddr::CIDR.create('192.168.1.0/24').subnet(:Bits => 26, :NumSubnets => 1)
1608
- #
1609
- #then I would get back the first /26 subnet of 192.168.1.0/24 and the remainder of the IP
1610
- #space as summary CIDR addresses (e.g. 192.168.1.0/26, 192.168.1.64/26, and 192.168.1.128/25).
1611
- #If I were to perform the same operation without the :NumSubnets directive, then 192.168.1.0/24
1612
- #will be fully subnetted into X number of /26 subnets (e.g. 192.168.1.0/26, 192.168.1.64/26,
1613
- #192.168.1.128/26, and 192.168.1.192/26).
1614
- #
1615
- #If neither :Bits nor :IPCount is provided, then the current CIDR will be split in half.
1616
- #If both :Bits and :IPCount are provided, then :Bits takes precedence.
1617
- #
1618
- # Example:
1619
- # cidr4 = NetAddr::CIDR.create('192.168.1.0/24')
1620
- # cidr6 = NetAddr::CIDR.create('fec0::/64')
1621
- # cidr4.subnet(:Bits => 28, :NumSubnets => 3)
1622
- # cidr4.subnet(:IPCount => 19)
1623
- # cidr4.subnet(:Bits => 28)
1624
- # cidr6.subnet(:Bits => 67, :NumSubnets => 4, :Short => true)
1625
- #
1626
- #===Arguments:
1627
- #* options = Hash with the following keys:
1628
- # :Bits -- Netmask (in bits) of new subnets - Integer
1629
- # :IPCount -- Minimum number of IP's that new subnets should contain - Integer
1630
- # :NumSubnets -- Number of X sized subnets to return - Integer
1631
- # :Objectify -- if true, return NetAddr::CIDR objects
1632
- # :Short -- if true, return IPv6 addresses in short-hand notation
1633
- #
1634
- #===Returns:
1635
- #* Array of Strings, or Array of NetAddr::CIDR objects
1636
- #
1637
- def subnet(options=nil)
1638
- known_args = [:Bits, :IPCount, :NumSubnets, :Objectify, :Short]
1639
- my_network = self.to_i(:network)
1640
- my_mask = self.bits
1641
- subnet_bits = my_mask + 1
1642
- min_count = nil
1643
- objectify = false
1644
- short = false
1645
-
1646
- if (options)
1647
- if (!options.kind_of? Hash)
1648
- raise ArgumentError, "Expected Hash, but #{options.class} provided."
1649
- end
1650
- NetAddr.validate_args(options.keys,known_args)
1651
-
1652
- if ( options.has_key?(:IPCount) )
1653
- subnet_bits = NetAddr.ip_count_to_size(options[:IPCount], @version)
1654
- end
1655
-
1656
- if ( options.has_key?(:Bits) )
1657
- subnet_bits = options[:Bits]
1658
- end
1659
-
1660
- if ( options.has_key?(:NumSubnets) )
1661
- num_subnets = options[:NumSubnets]
1662
- end
1663
-
1664
- if( options.has_key?(:Short) && options[:Short] == true )
1665
- short = true
1666
- end
1667
-
1668
- if( options.has_key?(:Objectify) && options[:Objectify] == true )
1669
- objectify = true
1670
- end
1671
-
1672
- end
1673
-
1674
- # get number of subnets possible with the requested subnet_bits
1675
- num_avail = 2**(subnet_bits - my_mask)
1676
-
1677
- # get the number of bits in the next supernet and
1678
- # make sure num_subnets is a power of 2
1679
- bits_needed = 1
1680
- num_subnets = num_avail if (!num_subnets)
1681
- until (2**bits_needed >= num_subnets)
1682
- bits_needed += 1
1683
- end
1684
- num_subnets = 2**bits_needed
1685
- next_supernet_bits = subnet_bits - bits_needed
1686
-
1687
-
1688
- # make sure subnet isnt bigger than available bits
1689
- if (subnet_bits > @address_len)
1690
- raise BoundaryError, "Requested subnet (#{subnet_bits}) does not fit " +
1691
- "within the bounds of IPv#{@version}."
1692
- end
1693
-
1694
- # make sure subnet is larger than mymask
1695
- if (subnet_bits < my_mask)
1696
- raise BoundaryError, "Requested subnet (#{subnet_bits}) is too large for " +
1697
- "current CIDR space."
1698
- end
1699
-
1700
- # make sure MinCount is smaller than available subnets
1701
- if (num_subnets > num_avail)
1702
- raise "Requested subnet count (#{num_subnets}) exceeds subnets " +
1703
- "available for allocation (#{num_avail})."
1704
- end
1705
-
1706
- # list all 'subnet_bits' sized subnets of this cidr block
1707
- # with a limit of num_subnets
1708
- bitstep = 2**(@address_len - subnet_bits)
1709
- subnets = self.enumerate(:Bitstep => bitstep, :Limit => num_subnets, :Objectify => true)
1710
-
1711
- # save our subnets
1712
- new_subnets = []
1713
- subnets.each do |subnet|
1714
- if (!objectify)
1715
- if (short && @version == 6)
1716
- new_subnets.push("#{subnet.network(:Short => true)}/#{subnet_bits}")
1717
- else
1718
- new_subnets.push("#{subnet.network}/#{subnet_bits}")
1719
- end
1720
- else
1721
- new_subnets.push( NetAddr.cidr_build(@version, subnet.to_i(:network), NetAddr.bits_to_mask(subnet_bits,version) ) )
1722
- end
1723
- end
1724
-
1725
- # now go through the rest of the cidr space and make the rest
1726
- # of the subnets. we want these to be as tightly merged as possible
1727
- next_supernet_bitstep = (bitstep * num_subnets)
1728
- next_supernet_ip = my_network + next_supernet_bitstep
1729
- until (next_supernet_bits == my_mask)
1730
- if (!objectify)
1731
- next_network = NetAddr.ip_int_to_str(next_supernet_ip, @version)
1732
- next_network = NetAddr.shorten(next_network) if (short && @version == 6)
1733
- new_subnets.push("#{next_network}/#{next_supernet_bits}")
1734
- else
1735
- new_subnets.push(NetAddr.cidr_build(@version, next_supernet_ip, NetAddr.bits_to_mask(next_supernet_bits,version) ) )
1736
- end
1737
-
1738
- next_supernet_bits -= 1
1739
- next_supernet_ip = next_supernet_ip + next_supernet_bitstep
1740
- next_supernet_bitstep = next_supernet_bitstep << 1
1741
- end
1742
-
1743
- return(new_subnets)
1744
- end
1745
-
1746
- #===Synopsis
1747
- #Provide the next subnet following this CIDR object. The next subnet will
1748
- #be of the same size as the current CIDR object.
1749
- #
1750
- # Example:
1751
- # cidr = NetAddr::CIDR.create('192.168.1.0/24')
1752
- # cidr.succ => 192.168.2.0/24
1753
- #
1754
- #===Arguments:
1755
- #* none
1756
- #
1757
- #===Returns:
1758
- #* NetAddr::CIDR object.
1759
- #
1760
- def succ()
1761
- bitstep = 2**(@address_len - self.bits)
1762
- next_sub = @network + bitstep
1763
-
1764
- if (next_sub > @all_f)
1765
- raise BoundaryError, "Returned subnet is out of bounds for IPv#{@version}."
1766
- end
1767
-
1768
- next_sub = NetAddr.cidr_build(@version,next_sub,self.to_i(:netmask))
1769
-
1770
- return(next_sub)
1771
- end
1772
-
1773
- #===Synopsis
1774
- #Convert the requested attribute of the CIDR to an Integer.
1775
- # Example:
1776
- # cidr = NetAddr::CIDR.create('192.168.1.1/24')
1777
- # cidr.to_i => 3232235776
1778
- # cidr.to_i(:hostmask) => 255
1779
- # cidr.to_i(:ip) => 3232235777
1780
- # cidr.to_i(:netmask) => 4294967040
1781
- # cidr.to_i(:wildcard_mask) => 4294967040
1782
- #
1783
- #===Arguments:
1784
- #* attribute -- attribute of the CIDR to convert to an Integer (:hostmask, :ip, :netmask, :network, or :wildcard_mask).
1785
- #
1786
- #===Returns:
1787
- #* Integer
1788
- #
1789
- def to_i(attribute=:network)
1790
- if(attribute == :network)
1791
- return(@network)
1792
- elsif(attribute == :hostmask)
1793
- return(@hostmask)
1794
- elsif(attribute == :ip)
1795
- return(@ip)
1796
- elsif(attribute == :netmask)
1797
- return(@netmask)
1798
- elsif(attribute == :wildcard_mask)
1799
- return(@wildcard_mask)
1800
- else
1801
- raise ArgumentError, "Attribute is unrecognized. Must be :hostmask, :ip, :netmask, :network, or :wildcard_mask."
1802
- end
1803
- end
1804
-
1805
- #===Synopsis
1806
- #Returns network/netmask in CIDR format.
1807
- #
1808
- # Example:
1809
- # cidr4 = NetAddr::CIDR.create('192.168.1.1/24')
1810
- # cidr6 = NetAddr::CIDR.create('fec0::/64')
1811
- # cidr4.desc(:IP => true) => "192.168.1.1/24"
1812
- # cidr4.to_s => "192.168.1.0/24"
1813
- # cidr6.to_s(:Short => true) => "fec0::/64"
1814
- #
1815
- #===Arguments:
1816
- #* options = Optional hash with the following keys:
1817
- # :IP -- if true, return the original ip/netmask passed during initialization
1818
- # :Short -- if true, return IPv6 addresses in short-hand notation
1819
- #
1820
- #===Returns:
1821
- #* String
1822
- #
1823
- def to_s(options=nil)
1824
- known_args = [:IP, :Short]
1825
- short = false
1826
- orig_ip = false
1827
-
1828
- if (options)
1829
- if (!options.kind_of? Hash)
1830
- raise ArgumentError, "Expected Hash, but #{options.class} provided."
1831
- end
1832
- NetAddr.validate_args(options.keys,known_args)
1833
-
1834
- if (options.has_key?(:Short) && options[:Short] == true)
1835
- short = true
1836
- end
1837
-
1838
- if (options.has_key?(:IP) && options[:IP] == true)
1839
- orig_ip = true
1840
- end
1841
- end
1842
-
1843
- if (!orig_ip)
1844
- ip = NetAddr.ip_int_to_str(@network, @version)
1845
- else
1846
- ip = NetAddr.ip_int_to_str(@ip, @version)
1847
- end
1848
- ip = NetAddr.shorten(ip) if (short && @version == 6)
1849
- mask = NetAddr.mask_to_bits(@netmask)
1850
-
1851
- return("#{ip}/#{mask}")
1852
- end
1853
-
1854
- #===Synopsis
1855
- #Return the wildcard mask.
1856
- #
1857
- # Example:
1858
- # cidr = NetAddr::CIDR.create('10.1.0.0/24', :WildcardMask => ['0.7.0.255', true])
1859
- # cidr.wildcard_mask => "255.248.255.0"
1860
- # cidr.wildcard_mask(true) => "0.7.0.255"
1861
- #
1862
- #===Arguments:
1863
- #* bit_flipped = if set True then returned the bit-flipped version of the wildcard mask.
1864
- #
1865
- #===Returns:
1866
- #* String
1867
- #
1868
- def wildcard_mask(bit_flipped=false)
1869
- ret_val = nil
1870
- if (!bit_flipped)
1871
- ret_val = NetAddr.ip_int_to_str(@wildcard_mask, @version)
1872
- else
1873
- ret_val = NetAddr.ip_int_to_str(~@wildcard_mask, @version)
1874
- end
1875
-
1876
- return(ret_val)
1877
- end
1878
-
1879
- end # end class CIDR
1880
-
1881
-
1882
-
1883
-
1884
-
1885
- # IPv4 CIDR address - Inherits all methods from NetAddr::CIDR.
1886
- # Addresses of this class are composed of a 32-bit address space.
1887
- class CIDRv4 < CIDR
1888
-
1889
- public_class_method :new
1890
-
1891
- # Alias for last
1892
- alias :broadcast :last
1893
-
1894
- #===Synopsis
1895
- #Provide IPv4 Hostmask in extended format (y.y.y.y).
1896
- #
1897
- # Example:
1898
- # cidr = NetAddr::CIDR.create('10.1.0.0/24')
1899
- # cidr.hostmask_ext => "0.0.0.255"
1900
- #
1901
- #===Arguments:
1902
- #* none
1903
- #
1904
- #===Returns:
1905
- #* String
1906
- #
1907
- def hostmask_ext()
1908
- return(NetAddr.ip_int_to_str(@hostmask, @version))
1909
- end
1910
-
1911
- #===Synopsis
1912
- #Provide IPv4 netmask in extended format (y.y.y.y).
1913
- #
1914
- # Example:
1915
- # cidr = NetAddr::CIDR.create('10.1.0.0/24')
1916
- # cidr.netmask_ext => "255.255.255.0"
1917
- #
1918
- #===Arguments:
1919
- #* none
1920
- #
1921
- #===Returns:
1922
- #* String
1923
- #
1924
- def netmask_ext()
1925
- return(NetAddr.ip_int_to_str(@netmask, 4))
1926
- end
1927
-
1928
- end # end class CIDRv4
1929
-
1930
-
1931
-
1932
-
1933
-
1934
-
1935
-
1936
-
1937
- # IPv6 CIDR address - Inherits all methods from NetAddr::CIDR.
1938
- # Addresses of this class are composed of a 128-bit address space.
1939
- class CIDRv6 < CIDR
1940
- public_class_method :new
1941
-
1942
- #===Synopsis
1943
- #Generate an IPv6 Unique Local CIDR address based on the algorithm described
1944
- #in RFC 4193.
1945
- #
1946
- #From the RFC:
1947
- #
1948
- # 1) Obtain the current time of day in 64-bit NTP format [NTP].
1949
- #
1950
- # 2) Obtain an EUI-64 identifier from the system running this
1951
- # algorithm. If an EUI-64 does not exist, one can be created from
1952
- # a 48-bit MAC address as specified in [ADDARCH]. If an EUI-64
1953
- # cannot be obtained or created, a suitably unique identifier,
1954
- # local to the node, should be used (e.g., system serial number).
1955
- #
1956
- # 3) Concatenate the time of day with the system-specific identifier
1957
- # in order to create a key.
1958
- #
1959
- # 4) Compute an SHA-1 digest on the key as specified in [FIPS, SHA1];
1960
- # the resulting value is 160 bits.
1961
- #
1962
- # 5) Use the least significant 40 bits as the Global ID.
1963
- #
1964
- # 6) Concatenate FC00::/7, the L bit set to 1, and the 40-bit Global
1965
- # ID to create a Local IPv6 address prefix.
1966
- #
1967
- # Example:
1968
- # eui = NetAddr::EUI.create('aabb.ccdd.eeff')
1969
- # NetAddr::CIDRv6.unique_local(eui) => fdb4:3014:e277:0000:0000:0000:0000:0000/48
1970
- #
1971
- #===Arguments:
1972
- #* NetAddr::EUI object
1973
- #
1974
- #===Returns:
1975
- #* CIDRv6 object
1976
- #
1977
- def CIDRv6.unique_local(eui)
1978
-
1979
- if (eui.kind_of?(NetAddr::EUI48) )
1980
- eui = eui.to_eui64.to_s
1981
- elsif (eui.kind_of?(NetAddr::EUI64) )
1982
- eui = eui.to_s
1983
- else
1984
- raise ArgumentError, "Expected NetAddr::EUI object but #{eui.class} received."
1985
- end
1986
-
1987
- ntp_time = ''
1988
-
1989
- # get current time (32-bits), convert to 4-byte string, and append to ntp_time
1990
- time = Time.now.to_i
1991
- 4.times do
1992
- ntp_time.insert(0, (time & 0xff).chr )
1993
- time = time >> 8
1994
- end
1995
-
1996
- # create 32-bit fractional, convert to 4-byte string, and append to ntp_time
1997
- fract = rand(2**32-1)
1998
- 4.times do
1999
- ntp_time.insert(0, (fract & 0xff).chr )
2000
- fract = fract >> 8
2001
- end
2002
-
2003
- # create sha1 hash
2004
- pre_hash = ntp_time << eui
2005
- gid = Digest::SHA1.hexdigest(pre_hash).slice!(30..39)
2006
- addr = 'fd' << gid << '00000000000000000000'
2007
-
2008
- return( NetAddr::CIDRv6.new(addr.to_i(16), 0xffffffffffff00000000000000000000 ) )
2009
- end
2010
-
2011
- end # end class CIDRv6
2012
-
2013
- end # module NetAddr
2014
- __END__