netaddr 1.5.0 → 2.0.4

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