netaddr 1.5.1 → 2.0.3

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,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__