netaddr 1.5.3 → 2.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/lib/methods.rb DELETED
@@ -1,1013 +0,0 @@
1
- module NetAddr
2
-
3
- #===Synopsis
4
- #Convert an Integer representing a binary netmask into an Integer representing
5
- #the number of bits in that netmask.
6
- #
7
- # Example:
8
- # NetAddr.i_to_bits(0xfffffffe) => 31
9
- # NetAddr.i_to_bits(0xffffffffffffffff0000000000000000) => 64
10
- #
11
- #===Arguments:
12
- #* netmask_int = Integer representing a binary netmask
13
- #
14
- #===Returns:
15
- #* Integer
16
- #
17
- def i_to_bits(netmask_int)
18
-
19
- # validate netmask_int
20
- raise ArgumentError, "Integer expected for argument 'netmask_int', " +
21
- "but #{netmask_int.class} provided." if (!netmask_int.kind_of?(Integer))
22
-
23
-
24
- return( mask_to_bits(netmask_int) )
25
- end
26
- module_function :i_to_bits
27
-
28
- #===Synopsis
29
- #Convert an Integer into an IP address. This method will attempt to auto-detect the IP version
30
- #if not provided, however, a slight speed increase is realized if version is provided.
31
- #
32
- # Example:
33
- # NetAddr.i_to_ip(3232235906) => "192.168.1.130"
34
- # NetAddr.i_to_ip(0xffff0000000000000000000000000001, :Version => 6) => "ffff:0000:0000:0000:0000:0000:0000:0001"
35
- #
36
- #===Arguments:
37
- #* ip_int = IP address as an Integer
38
- #* options = Hash with the following keys:
39
- # :Version -- IP version - Integer (optional)
40
- # :IPv4Mapped -- if true, unpack IPv6 as an IPv4 mapped address (optional)
41
- #
42
- #===Returns:
43
- #* String
44
- #
45
- def i_to_ip(ip_int, options=nil)
46
- known_args = [:Version, :IPv4Mapped]
47
- ipv4_mapped = false
48
- version = nil
49
-
50
- # validate options
51
- if (options)
52
- raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash))
53
- NetAddr.validate_args(options.keys,known_args)
54
-
55
- if (options.has_key?(:Version))
56
- version = options[:Version]
57
- if (version != 4 && version != 6)
58
- raise VersionError, ":Version should be 4 or 6, but was '#{version}'."
59
- end
60
- end
61
-
62
- if (options.has_key?(:IPv4Mapped) && options[:IPv4Mapped] == true)
63
- ipv4_mapped = true
64
- end
65
- end
66
-
67
- # validate & unpack
68
- raise ArgumentError, "Integer expected for argument 'ip_int', " +
69
- "but #{ip_int.class} provided." if (!ip_int.kind_of?(Integer))
70
- version = validate_ip_int(ip_int, version)
71
- ip = ip_int_to_str(ip_int, version, ipv4_mapped)
72
-
73
- return(ip)
74
- end
75
- module_function :i_to_ip
76
-
77
- #===Synopsis
78
- #Convert IP addresses into an Integer. This method will attempt to auto-detect the IP version
79
- #if not provided, however a slight speed increase is realized if version is provided.
80
- #
81
- # Example:
82
- # NetAddr.ip_to_i('192.168.1.1') => 3232235777
83
- # NetAddr.ip_to_i('ffff::1', :Version => 6) => 340277174624079928635746076935438991361
84
- # NetAddr.ip_to_i('::192.168.1.1') => 3232235777
85
- #
86
- #===Arguments:
87
- #* ip = IP address as a String
88
- #* options = Hash with the following keys:
89
- # :Version -- IP version - Integer
90
- #
91
- #===Returns:
92
- #* Integer
93
- #
94
- def ip_to_i(ip, options=nil)
95
- known_args = [:Version]
96
- to_validate = {}
97
- version = nil
98
-
99
- # validate options
100
- if (options)
101
- raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash))
102
- validate_args(options.keys,known_args)
103
-
104
- if (options.has_key?(:Version))
105
- version = options[:Version]
106
- to_validate[:Version] = version
107
- if (version != 4 && version != 6)
108
- raise VersionError, ":Version should be 4 or 6, but was '#{version}'."
109
- end
110
- end
111
- end
112
-
113
- if ( ip.kind_of?(String) )
114
- version = detect_ip_version(ip) if (!version)
115
- validate_ip_str(ip,version)
116
- ip_int = ip_str_to_int(ip,version)
117
-
118
- else
119
- raise ArgumentError, "String expected for argument 'ip' but #{ip.class} provided."
120
- end
121
-
122
- return(ip_int)
123
- end
124
- module_function :ip_to_i
125
-
126
- #===Synopsis
127
- #Given a list of CIDR addresses or NetAddr::CIDR objects,
128
- #merge (summarize) them in the most efficient way possible. Summarization
129
- #will only occur when the newly created supernets will not result in the
130
- #'creation' of new IP space. For example the following blocks
131
- #(192.168.0.0/24, 192.168.1.0/24, and 192.168.2.0/24) would be summarized into
132
- #192.168.0.0/23 and 192.168.2.0/24 rather than into 192.168.0.0/22
133
- #
134
- #I have designed this with enough flexibility so that you can pass in CIDR
135
- #addresses that arent even related (ex. 192.168.1.0/26, 192.168.1.64/27, 192.168.1.96/27
136
- #10.1.0.0/26, 10.1.0.64/26) and they will be merged properly (ie 192.168.1.0/25,
137
- #and 10.1.0.0/25 would be returned).
138
- #
139
- #If the :Objectify option is enabled, then any summary addresses returned will
140
- #contain the original CIDRs used to create them within the tag value :Subnets
141
- #(ie. cidr_x.tag[:Subnets] would be an Array of the CIDRs used to create cidr_x)
142
- #
143
- # Example:
144
- # cidr1 = NetAddr::CIDR.create('192.168.1.0/27')
145
- # cidr2 = NetAddr::CIDR.create('192.168.1.32/27')
146
- # NetAddr.merge([cidr1,cidr2])
147
- # ip_net_range = NetAddr.range('192.168.35.0','192.168.39.255',:Inclusive => true, :Objectify => true)
148
- # NetAddr.merge(ip_net_range, :Objectify => true)
149
- #
150
- #===Arguments:
151
- #* list = Array of CIDR addresses as Strings, or an Array of NetAddr::CIDR objects
152
- #* options = Hash with the following keys:
153
- # :Objectify -- if true, return NetAddr::CIDR objects
154
- # :Short -- if true, return IPv6 addresses in short-hand notation
155
- #
156
- #===Returns:
157
- #* Array of CIDR addresses or NetAddr::CIDR objects
158
- #
159
- def merge(list,options=nil)
160
- known_args = [:Objectify, :Short]
161
- short = false
162
- objectify = false
163
- verbose = false
164
-
165
- # validate list
166
- raise ArgumentError, "Array expected for argument 'list' but #{list.class} provided." if (!list.kind_of?(Array) )
167
-
168
- # validate options
169
- if (options)
170
- raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash) )
171
- NetAddr.validate_args(options.keys,known_args)
172
-
173
- if (options.has_key?(:Objectify) && options[:Objectify] == true)
174
- objectify = true
175
- end
176
-
177
- if (options.has_key?(:Short) && options[:Short] == true)
178
- short = true
179
- end
180
- end
181
-
182
- # make sure all are valid types of the same IP version
183
- v4_list = []
184
- v6_list = []
185
- list.each do |obj|
186
- if (!obj.kind_of?(NetAddr::CIDR))
187
- begin
188
- obj = NetAddr::CIDR.create(obj)
189
- rescue Exception => error
190
- raise ArgumentError, "One of the provided CIDR addresses raised the following " +
191
- "errors: #{error}"
192
- end
193
- end
194
-
195
- if (obj.version == 4)
196
- v4_list.push(obj)
197
- else
198
- v6_list.push(obj)
199
- end
200
- end
201
-
202
- # summarize
203
- v4_summary = []
204
- v6_summary = []
205
- if (v4_list.length != 0)
206
- v4_summary = NetAddr.cidr_summarize(v4_list)
207
- end
208
-
209
- if (v6_list.length != 0)
210
- v6_summary = NetAddr.cidr_summarize(v6_list)
211
- end
212
-
213
- # decide what to return
214
- summarized_list = []
215
- if (!objectify)
216
- summarized_list = []
217
- if (v4_summary.length != 0)
218
- v4_summary.each {|x| summarized_list.push(x.desc())}
219
- end
220
-
221
- if (v6_summary.length != 0)
222
- v6_summary.each {|x| summarized_list.push(x.desc(:Short => short))}
223
- end
224
-
225
- else
226
- summarized_list.concat(v4_summary) if (v4_summary.length != 0)
227
- summarized_list.concat(v6_summary) if (v6_summary.length != 0)
228
- end
229
-
230
- return(summarized_list)
231
- end
232
- module_function :merge
233
-
234
- #===Synopsis
235
- #Given the number of IP addresses required in a subnet, return the minimum
236
- #netmask (bits by default) required for that subnet. IP version is assumed to be 4 unless specified otherwise.
237
- #
238
- # Example:
239
- # NetAddr.minimum_size(14) => 28
240
- # NetAddr.minimum_size(65536, :Version => 6) => 112
241
- #
242
- #===Arguments:
243
- #* ipcount = IP count as an Integer
244
- #* options = Hash with the following keys:
245
- # :Extended -- If true, then return the netmask, as a String, in extended format (IPv4 only y.y.y.y)
246
- # :Version -- IP version - Integer
247
- #
248
- #===Returns:
249
- #* Integer or String
250
- #
251
- def minimum_size(ipcount, options=nil)
252
- version = 4
253
- extended = false
254
- known_args = [:Version, :Extended]
255
-
256
- # validate ipcount
257
- raise ArgumentError, "Integer expected for argument 'ipcount' but #{ipcount.class} provided." if (!ipcount.kind_of?(Integer))
258
-
259
- # validate options
260
- if (options)
261
- raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash))
262
-
263
- NetAddr.validate_args(options.keys,known_args)
264
-
265
- if (options.has_key?(:Version))
266
- version = options[:Version]
267
- end
268
-
269
- if (options.has_key?(:Extended) && options[:Extended] == true)
270
- extended = true
271
- end
272
- end
273
-
274
- return( ip_count_to_size(ipcount,version,extended) )
275
- end
276
- module_function :minimum_size
277
-
278
- #===Synopsis
279
- #Convert IP netmask into an Integer. Netmask may be in either CIDR (/yy) or
280
- #extended (y.y.y.y) format. CIDR formatted netmasks may either
281
- #be a String or an Integer. IP version defaults to 4. It may be necessary
282
- #to specify the version if an IPv6 netmask of /32 or smaller is provided.
283
- #
284
- # Example:
285
- # NetAddr.netmask_to_i('255.255.255.0') => 4294967040
286
- # NetAddr.netmask_to_i('24') => 4294967040
287
- # NetAddr.netmask_to_i(24) => 4294967040
288
- # NetAddr.netmask_to_i('/24') => 4294967040
289
- # NetAddr.netmask_to_i('32', :Version => 6) => 340282366841710300949110269838224261120
290
- #
291
- #===Arguments
292
- #* netmask = Netmask as a String or Integer
293
- #* options = Hash with the following keys:
294
- # :Version -- IP version - Integer
295
- #
296
- #===Returns:
297
- #* Integer
298
- #
299
- def netmask_to_i(netmask, options=nil)
300
- known_args = [:Version]
301
- version = 4
302
- netmask_int = nil
303
-
304
- # validate options
305
- if (options)
306
- raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash))
307
- NetAddr.validate_args(options.keys,known_args)
308
-
309
- if (options.has_key?(:Version))
310
- version = options[:Version]
311
- if (version != 4 && version != 6)
312
- raise VersionError, ":Version should be 4 or 6, but was '#{version}'."
313
- end
314
- end
315
- end
316
-
317
- if (netmask.kind_of?(String))
318
- validate_netmask_str(netmask, version)
319
- netmask_int = netmask_str_to_int(netmask,version)
320
-
321
- elsif (netmask.kind_of?(Integer))
322
- validate_netmask_int(netmask, version, true)
323
- netmask_int = bits_to_mask(netmask,version)
324
-
325
- else
326
- raise ArgumentError, "String or Integer expected for argument 'netmask', " +
327
- "but #{netmask.class} provided." if (!netmask.kind_of?(Integer) && !netmask.kind_of?(String))
328
- end
329
-
330
- return(netmask_int)
331
- end
332
- module_function :netmask_to_i
333
-
334
- #===Synopsis
335
- #Given two CIDR addresses or NetAddr::CIDR objects of the same version,
336
- #return all IP addresses between them. NetAddr.range will use the original IP
337
- #address passed during the initialization of the NetAddr::CIDR objects, or the
338
- #IP address portion of any CIDR addresses passed. The default behavior is to be
339
- #non-inclusive (don't include boundaries as part of returned data).
340
- #
341
- # Example:
342
- # lower = NetAddr::CIDR.create('192.168.35.0')
343
- # upper = NetAddr::CIDR.create('192.168.39.255')
344
- # NetAddr.range(lower,upper, :Limit => 10, :Bitstep => 32)
345
- # NetAddr.range('192.168.35.0','192.168.39.255', :Inclusive => true)
346
- # NetAddr.range('192.168.35.0','192.168.39.255', :Inclusive => true, :Size => true)
347
- #
348
- #===Arguments:
349
- #* lower = Lower boundary CIDR as a String or NetAddr::CIDR object
350
- #* upper = Upper boundary CIDR as a String or NetAddr::CIDR object
351
- #* options = Hash with the following keys:
352
- # :Bitstep -- enumerate in X sized steps - Integer
353
- # :Inclusive -- if true, include boundaries in returned data
354
- # :Limit -- limit returned list to X number of items - Integer
355
- # :Objectify -- if true, return CIDR objects
356
- # :Short -- if true, return IPv6 addresses in short-hand notation
357
- # :Size -- if true, return the number of addresses in this range, but not the addresses themselves
358
- #
359
- #===Returns:
360
- #* Array of Strings or NetAddr::CIDR objects, or an Integer
361
- #
362
- #===Note:
363
- #If you do not need all of the fancy options in this method, then please consider
364
- #using the standard Ruby Range class as shown below.
365
- #
366
- # Example:
367
- # start = NetAddr::CIDR.create('192.168.1.0')
368
- # fin = NetAddr::CIDR.create('192.168.2.3')
369
- # (start..fin).each {|addr| puts addr.desc}
370
- #
371
- def range(lower, upper, options=nil)
372
- known_args = [:Bitstep, :Inclusive, :Limit, :Objectify, :Short, :Size]
373
- list = []
374
- bitstep = 1
375
- objectify = false
376
- short = false
377
- size_only = false
378
- inclusive = false
379
- limit = nil
380
-
381
- # if lower/upper are not CIDR objects, then attempt to create
382
- # cidr objects from them
383
- if ( !lower.kind_of?(NetAddr::CIDR) )
384
- begin
385
- lower = NetAddr::CIDR.create(lower)
386
- rescue Exception => error
387
- raise ArgumentError, "Argument 'lower' raised the following " +
388
- "errors: #{error}"
389
- end
390
- end
391
-
392
- if ( !upper.kind_of?(NetAddr::CIDR))
393
- begin
394
- upper = NetAddr::CIDR.create(upper)
395
- rescue Exception => error
396
- raise ArgumentError, "Argument 'upper' raised the following " +
397
- "errors: #{error}"
398
- end
399
- end
400
-
401
- # validate options
402
- if (options)
403
- raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash))
404
- NetAddr.validate_args(options.keys,known_args)
405
-
406
- if( options.has_key?(:Bitstep) )
407
- bitstep = options[:Bitstep]
408
- end
409
-
410
- if( options.has_key?(:Objectify) && options[:Objectify] == true )
411
- objectify = true
412
- end
413
-
414
- if( options.has_key?(:Short) && options[:Short] == true )
415
- short = true
416
- end
417
-
418
- if( options.has_key?(:Size) && options[:Size] == true )
419
- size_only = true
420
- end
421
-
422
- if( options.has_key?(:Inclusive) && options[:Inclusive] == true )
423
- inclusive = true
424
- end
425
-
426
- if( options.has_key?(:Limit) )
427
- limit = options[:Limit]
428
- end
429
- end
430
-
431
- # check version, store & sort
432
- if (lower.version == upper.version)
433
- version = lower.version
434
- boundaries = [lower.to_i(:ip), upper.to_i(:ip)]
435
- boundaries.sort
436
- else
437
- raise VersionError, "Provided NetAddr::CIDR objects are of different IP versions."
438
- end
439
-
440
- # dump our range
441
- if (!inclusive)
442
- my_ip = boundaries[0] + 1
443
- end_ip = boundaries[1]
444
- else
445
- my_ip = boundaries[0]
446
- end_ip = boundaries[1] + 1
447
- end
448
-
449
- if (!size_only)
450
- until (my_ip >= end_ip)
451
- if (!objectify)
452
- my_ip_s = ip_int_to_str(my_ip, version)
453
- my_ips = shorten(my_ips) if (short && version == 6)
454
- list.push(my_ip_s)
455
- else
456
- list.push( cidr_build(version,my_ip) )
457
- end
458
-
459
- my_ip = my_ip + bitstep
460
- if (limit)
461
- limit = limit - 1
462
- break if (limit == 0)
463
- end
464
- end
465
- else
466
- list = end_ip - my_ip
467
- end
468
-
469
- return(list)
470
- end
471
- module_function :range
472
-
473
- #===Synopsis
474
- #Take a standard IPv6 address and format it in short-hand notation.
475
- #The address should not contain a netmask.
476
- #
477
- # Example:
478
- # NetAddr.shorten('fec0:0000:0000:0000:0000:0000:0000:0001') => "fec0::1"
479
- #
480
- #===Arguments:
481
- #* addr = String
482
- #
483
- #===Returns:
484
- #* String
485
- #
486
- def shorten(addr)
487
-
488
- # is this a string?
489
- if (!addr.kind_of? String)
490
- raise ArgumentError, "Expected String, but #{addr.class} provided."
491
- end
492
-
493
- validate_ip_str(addr, 6)
494
-
495
- # make sure this isnt already shorthand
496
- if (addr =~ /::/)
497
- return(addr)
498
- end
499
-
500
- # split into fields
501
- fields = addr.split(":")
502
-
503
- # check last field for ipv4-mapped addr
504
- if (fields.last() =~ /\./ )
505
- ipv4_mapped = fields.pop()
506
- end
507
-
508
- # look for most consecutive '0' fields
509
- start_field,end_field = nil,nil
510
- start_end = []
511
- consecutive,longest = 0,0
512
-
513
- (0..(fields.length-1)).each do |x|
514
- fields[x] = fields[x].to_i(16)
515
-
516
- if (fields[x] == 0)
517
- if (!start_field)
518
- start_field = x
519
- end_field = x
520
- else
521
- end_field = x
522
- end
523
- consecutive += 1
524
- else
525
- if (start_field)
526
- if (consecutive > longest)
527
- longest = consecutive
528
- start_end = [start_field,end_field]
529
- start_field,end_field = nil,nil
530
- end
531
- consecutive = 0
532
- end
533
- end
534
-
535
- fields[x] = fields[x].to_s(16)
536
- end
537
-
538
- # if our longest set of 0's is at the end, then start & end fields
539
- # are already set. if not, then make start & end fields the ones we've
540
- # stored away in start_end
541
- if (consecutive > longest)
542
- longest = consecutive
543
- else
544
- start_field = start_end[0]
545
- end_field = start_end[1]
546
- end
547
-
548
- if (longest > 1)
549
- fields[start_field] = ''
550
- start_field += 1
551
- fields.slice!(start_field..end_field)
552
- end
553
- fields.push(ipv4_mapped) if (ipv4_mapped)
554
- short = fields.join(':')
555
- short << ':' if (short =~ /:$/)
556
-
557
- return(short)
558
- end
559
- module_function :shorten
560
-
561
- #===Synopsis
562
- #Sort a list of CIDR addresses or NetAddr::CIDR objects,
563
- #
564
- # Example:
565
- # cidr1 = NetAddr::CIDR.create('192.168.1.32/27')
566
- # cidr2 = NetAddr::CIDR.create('192.168.1.0/27')
567
- # NetAddr.sort([cidr1,cidr2])
568
- # NetAddr.sort(['192.168.1.32/27','192.168.1.0/27','192.168.2.0/24'], :Desc => true)
569
- #
570
- #===Arguments:
571
- #* list = Array of CIDR addresses as Strings, or Array of NetAddr::CIDR objects
572
- #* options = Hash with the following keys:
573
- # :ByMask -- if true, sorts based on the netmask length
574
- # :Desc -- if true, return results in descending order
575
- #
576
- #===Returns:
577
- #* Array of Strings, or Array of NetAddr::CIDR objects
578
- #
579
- def sort(list, options=nil)
580
- # make sure list is an array
581
- if ( !list.kind_of?(Array) )
582
- raise ArgumentError, "Array of NetAddr::CIDR or NetStruct " +
583
- "objects expected, but #{list.class} provided."
584
- end
585
-
586
- desc = false
587
- by_mask = false
588
- # validate options
589
- if (options)
590
- known_args = [:Desc, :ByMask]
591
- raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash))
592
- NetAddr.validate_args(options.keys,known_args)
593
-
594
- if( options.has_key?(:Desc) && options[:Desc] == true )
595
- desc = true
596
- end
597
-
598
- if( options.has_key?(:ByMask) && options[:ByMask] == true )
599
- by_mask = true
600
- end
601
-
602
- end
603
-
604
- # make sure all are valid types of the same IP version
605
- version = nil
606
- cidr_hash = {}
607
- list.each do |cidr|
608
- if (!cidr.kind_of?(NetAddr::CIDR))
609
- begin
610
- new_cidr = NetAddr::CIDR.create(cidr)
611
- rescue Exception => error
612
- raise ArgumentError, "An element of the provided Array " +
613
- "raised the following errors: #{error}"
614
- end
615
- else
616
- new_cidr = cidr
617
- end
618
- cidr_hash[new_cidr] = cidr
619
-
620
- version = new_cidr.version if (!version)
621
- unless (new_cidr.version == version)
622
- raise VersionError, "Provided CIDR addresses must all be of the same IP version."
623
- end
624
- end
625
-
626
- # perform sort
627
- if (by_mask)
628
- sorted_list = netmask_sort(cidr_hash.keys, desc)
629
- else
630
- sorted_list = cidr_sort(cidr_hash.keys, desc)
631
- end
632
-
633
- # return original values passed
634
- ret_list = []
635
- sorted_list.each {|x| ret_list.push(cidr_hash[x])}
636
-
637
- return(ret_list)
638
- end
639
- module_function :sort
640
-
641
- #===Synopsis
642
- #Given a list of CIDR addresses or NetAddr::CIDR objects,
643
- #return only the top-level supernet CIDR addresses.
644
- #
645
- #
646
- #If the :Objectify option is enabled, then returned CIDR objects will
647
- #store the more specific CIDRs (i.e. subnets of those CIDRs) within the tag value :Subnets
648
- #For example, cidr_x.tag[:Subnets] would be an Array of CIDR subnets of cidr_x.
649
- #
650
- # Example:
651
- # NetAddr.supernets(['192.168.0.0', '192.168.0.1', '192.168.0.0/31'])
652
- #
653
- #===Arguments:
654
- #* list = Array of CIDR addresses as Strings, or an Array of NetAddr::CIDR objects
655
- #* options = Hash with the following keys:
656
- # :Objectify -- if true, return NetAddr::CIDR objects
657
- # :Short -- if true, return IPv6 addresses in short-hand notation
658
- #
659
- #===Returns:
660
- #* Array of CIDR addresses or NetAddr::CIDR objects
661
- #
662
- def supernets(list,options=nil)
663
- known_args = [:Objectify, :Short]
664
- short = false
665
- objectify = false
666
- verbose = false
667
-
668
- # validate list
669
- raise ArgumentError, "Array expected for argument 'list' but #{list.class} provided." if (!list.kind_of?(Array) )
670
-
671
- # validate options
672
- if (options)
673
- raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash) )
674
- NetAddr.validate_args(options.keys,known_args)
675
-
676
- if (options.has_key?(:Objectify) && options[:Objectify] == true)
677
- objectify = true
678
- end
679
-
680
- if (options.has_key?(:Short) && options[:Short] == true)
681
- short = true
682
- end
683
- end
684
-
685
- # make sure all are valid types of the same IP version
686
- v4_list = []
687
- v6_list = []
688
- list.each do |obj|
689
- if (!obj.kind_of?(NetAddr::CIDR))
690
- begin
691
- obj = NetAddr::CIDR.create(obj)
692
- rescue Exception => error
693
- raise ArgumentError, "One of the provided CIDR addresses raised the following " +
694
- "errors: #{error}"
695
- end
696
- end
697
-
698
- if (obj.version == 4)
699
- v4_list.push(obj)
700
- else
701
- v6_list.push(obj)
702
- end
703
- end
704
-
705
- # do summary calcs
706
- v4_summary = []
707
- v6_summary = []
708
- if (v4_list.length != 0)
709
- v4_summary = NetAddr.cidr_supernets(v4_list)
710
- end
711
-
712
- if (v6_list.length != 0)
713
- v6_summary = NetAddr.cidr_supernets(v6_list)
714
- end
715
-
716
- # decide what to return
717
- summarized_list = []
718
- if (!objectify)
719
- summarized_list = []
720
- if (v4_summary.length != 0)
721
- v4_summary.each {|x| summarized_list.push(x.desc())}
722
- end
723
-
724
- if (v6_summary.length != 0)
725
- v6_summary.each {|x| summarized_list.push(x.desc(:Short => short))}
726
- end
727
-
728
- else
729
- summarized_list.concat(v4_summary) if (v4_summary.length != 0)
730
- summarized_list.concat(v6_summary) if (v6_summary.length != 0)
731
- end
732
-
733
- return(summarized_list)
734
- end
735
- module_function :supernets
736
-
737
- #===Synopsis
738
- #Take an IPv6 address in short-hand format, and expand it into standard
739
- #notation. The address should not contain a netmask.
740
- #
741
- # Example:
742
- # NetAddr.unshorten('fec0::1') => "fec0:0000:0000:0000:0000:0000:0000:0001"
743
- #
744
- #===Arguments:
745
- #* ip = CIDR address as a String
746
- #
747
- #===Returns:
748
- #* String
749
- #
750
- def unshorten(ip)
751
-
752
- # is this a string?
753
- if (!ip.kind_of? String)
754
- raise ArgumentError, "Expected String, but #{ip.class} provided."
755
- end
756
-
757
- validate_ip_str(ip, 6)
758
- ipv4_mapped = true if (ip =~ /\./)
759
-
760
- ip_int = ip_to_i(ip, :Version => 6)
761
- if (!ipv4_mapped)
762
- long = ip_int_to_str(ip_int, 6)
763
- else
764
- long = ip_int_to_str(ip_int, 6, true)
765
- end
766
-
767
- return(long)
768
- end
769
- module_function :unshorten
770
-
771
- #===Synopsis
772
- #Validate an EUI-48 or EUI-64 address. Raises NetAddr::ValidationError on validation failure.
773
- #
774
- # Example:
775
- # NetAddr.validate_eui('01-00-5e-12-34-56') => true
776
- #
777
- # - Arguments
778
- #* eui = EUI address as a String
779
- #
780
- #===Returns:
781
- #* True
782
- #
783
- def validate_eui(eui)
784
- if (eui.kind_of?(String))
785
- # check for invalid characters
786
- if (eui =~ /[^0-9a-fA-F\.\-\:]/)
787
- raise ValidationError, "#{eui} is invalid (contains invalid characters)."
788
- end
789
-
790
- # split on formatting characters & check lengths
791
- if (eui =~ /\-/)
792
- fields = eui.split('-')
793
- if (fields.length != 6 && fields.length != 8)
794
- raise ValidationError, "#{eui} is invalid (unrecognized formatting)."
795
- end
796
- fields.each {|x| raise ValidationError, "#{eui} is invalid (missing characters)." if (x.length != 2)}
797
- elsif (eui =~ /\:/)
798
- fields = eui.split(':')
799
- if (fields.length != 6 && fields.length != 8)
800
- raise ValidationError, "#{eui} is invalid (unrecognized formatting)."
801
- end
802
- fields.each {|x| raise ValidationError, "#{eui} is invalid (missing characters)." if (x.length != 2)}
803
- elsif (eui =~ /\./)
804
- fields = eui.split('.')
805
- if (fields.length != 3 && fields.length != 4)
806
- raise ValidationError, "#{eui} is invalid (unrecognized formatting)."
807
- end
808
- fields.each {|x| raise ValidationError, "#{eui} is invalid (missing characters)." if (x.length != 4)}
809
- else
810
- raise ValidationError, "#{eui} is invalid (unrecognized formatting)."
811
- end
812
-
813
- else
814
- raise ArgumentError, "EUI address should be a String, but was a#{eui.class}."
815
- end
816
- return(true)
817
- end
818
- module_function :validate_eui
819
-
820
- #===Synopsis
821
- #Validate an IP address. The address should not contain a netmask.
822
- #This method will attempt to auto-detect the IP version
823
- #if not provided, however a slight speed increase is realized if version is provided.
824
- #Raises NetAddr::ValidationError on validation failure.
825
- #
826
- # Example:
827
- # NetAddr.validate_ip_addr('192.168.1.1') => true
828
- # NetAddr.validate_ip_addr('ffff::1', :Version => 6) => true
829
- # NetAddr.validate_ip_addr('::192.168.1.1') => true
830
- # NetAddr.validate_ip_addr(0xFFFFFF) => true
831
- # NetAddr.validate_ip_addr(2**128-1) => true
832
- # NetAddr.validate_ip_addr(2**32-1, :Version => 4) => true
833
- #
834
- #===Arguments
835
- #* ip = IP address as a String or Integer
836
- #* options = Hash with the following keys:
837
- # :Version -- IP version - Integer (optional)
838
- #
839
- #===Returns:
840
- #* True
841
- #
842
- def validate_ip_addr(ip, options=nil)
843
- known_args = [:Version]
844
- version = nil
845
-
846
- # validate options
847
- if (options)
848
- raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash))
849
- NetAddr.validate_args(options.keys,known_args)
850
-
851
- if (options.has_key?(:Version))
852
- version = options[:Version]
853
- if (version != 4 && version != 6)
854
- raise ArgumentError, ":Version should be 4 or 6, but was '#{version}'."
855
- end
856
- end
857
- end
858
-
859
- if ( ip.kind_of?(String) )
860
- version = NetAddr.detect_ip_version(ip) if (!version)
861
- NetAddr.validate_ip_str(ip,version)
862
-
863
- elsif ( ip.kind_of?(Integer) )
864
- NetAddr.validate_ip_int(ip,version)
865
-
866
- else
867
- raise ArgumentError, "Integer or String expected for argument 'ip' but " +
868
- "#{ip.class} provided." if (!ip.kind_of?(String) && !ip.kind_of?(Integer))
869
- end
870
-
871
- return(true)
872
- end
873
- module_function :validate_ip_addr
874
-
875
- #===Synopsis
876
- #Validate IP Netmask. Version defaults to 4 if not specified.
877
- #Raises NetAddr::ValidationError on validation failure.
878
- #
879
- # Examples:
880
- # NetAddr.validate_ip_netmask('/32') => true
881
- # NetAddr.validate_ip_netmask(32) => true
882
- # NetAddr.validate_ip_netmask(0xffffffff, :Integer => true) => true
883
- #
884
- #===Arguments:
885
- #* netmask = Netmask as a String or Integer
886
- #* options = Hash with the following keys:
887
- # :Integer -- if true, the provided Netmask is an Integer mask
888
- # :Version -- IP version - Integer (optional)
889
- #
890
- #===Returns:
891
- #* True
892
- #
893
- def validate_ip_netmask(netmask, options=nil)
894
- known_args = [:Integer, :Version]
895
- is_integer = false
896
- version = 4
897
-
898
- # validate options
899
- if (options)
900
- raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash))
901
- NetAddr.validate_args(options.keys,known_args)
902
-
903
- if (options.has_key?(:Integer) && options[:Integer] == true)
904
- is_integer = true
905
- end
906
-
907
- if (options.has_key?(:Version))
908
- version = options[:Version]
909
- if (version != 4 && version != 6)
910
- raise ArgumentError, ":Version should be 4 or 6, but was '#{version}'."
911
- end
912
- end
913
- end
914
-
915
- # validate netmask
916
- if (netmask.kind_of?(String))
917
- validate_netmask_str(netmask,version)
918
- elsif (netmask.kind_of?(Integer) )
919
- validate_netmask_int(netmask,version,is_integer)
920
- else
921
- raise ArgumentError, "Integer or String expected for argument 'netmask' but " +
922
- "#{netmask.class} provided." if (!netmask.kind_of?(String) && !netmask.kind_of?(Integer))
923
- end
924
-
925
- return(true)
926
- end
927
- module_function :validate_ip_netmask
928
-
929
- #===Synopsis
930
- #Convert a wildcard IP into a valid CIDR address. Wildcards must always be at
931
- #the end of the address. Any data located after the first wildcard will be lost.
932
- #Shorthand notation is prohibited for IPv6 addresses.
933
- #IPv6 encoded IPv4 addresses are not currently supported.
934
- #
935
- # Examples:
936
- # NetAddr.wildcard('192.168.*')
937
- # NetAddr.wildcard('192.168.1.*')
938
- # NetAddr.wildcard('fec0:*')
939
- # NetAddr.wildcard('fec0:1:*')
940
- #
941
- #===Arguments:
942
- #* ip = Wildcard IP address as a String
943
- #
944
- #===Returns:
945
- #* CIDR object
946
- #
947
- def wildcard(ip)
948
- version = 4
949
-
950
- # do operations per version of address
951
- if (ip =~ /\./ && ip !~ /:/)
952
- octets = []
953
- mask = 0
954
-
955
- ip.split('.').each do |x|
956
- if (x =~ /\*/)
957
- break
958
- end
959
- octets.push(x)
960
- end
961
-
962
- octets.length.times do
963
- mask = mask << 8
964
- mask = mask | 0xff
965
- end
966
-
967
- until (octets.length == 4)
968
- octets.push('0')
969
- mask = mask << 8
970
- end
971
- ip = octets.join('.')
972
-
973
- elsif (ip =~ /:/)
974
- version = 6
975
- fields = []
976
- mask = 0
977
-
978
- raise ArgumentError, "IPv6 encoded IPv4 addresses are unsupported." if (ip =~ /\./)
979
- raise ArgumentError, "Shorthand IPv6 addresses are unsupported." if (ip =~ /::/)
980
-
981
- ip.split(':').each do |x|
982
- if (x =~ /\*/)
983
- break
984
- end
985
- fields.push(x)
986
- end
987
-
988
- fields.length.times do
989
- mask = mask << 16
990
- mask = mask | 0xffff
991
- end
992
-
993
- until (fields.length == 8)
994
- fields.push('0')
995
- mask = mask << 16
996
- end
997
- ip = fields.join(':')
998
- end
999
-
1000
- # make & return cidr
1001
- cidr = cidr_build( version, ip_str_to_int(ip,version), mask )
1002
-
1003
- return(cidr)
1004
- end
1005
- module_function :wildcard
1006
-
1007
-
1008
-
1009
-
1010
- end # module NetAddr
1011
-
1012
- __END__
1013
-