netaddr 1.5.3 → 2.0.1

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

Potentially problematic release.


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

data/lib/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
-