From 138093889336bf4fc769b04941c59243a0ad0276 Mon Sep 17 00:00:00 2001 From: D062794 Date: Thu, 5 May 2022 11:25:47 +0200 Subject: [PATCH] Bump netaddr gem to 1.5.3 to fix CVE-2019-17383 Consume netaddr release from github since it hasn't been published on rubygems yet. For more context see: - https://github.com/dspinhirne/netaddr-rb/issues/29 - https://github.com/cloudfoundry/bosh/pull/2369 Co-authored-by: Shilpa Chandrashekara --- src/Gemfile | 1 + src/Gemfile.lock | 11 +- src/bosh-director/bosh-director.gemspec | 2 +- src/vendor/cache/netaddr-1.5.1.gem | Bin 41472 -> 0 bytes .../netaddr-rb-c7a7de39b7e1/.bundlecache | 0 .../cache/netaddr-rb-c7a7de39b7e1/Errors | 7 + .../cache/netaddr-rb-c7a7de39b7e1/README.md | 9 + .../cache/netaddr-rb-c7a7de39b7e1/changelog | 52 + .../cache/netaddr-rb-c7a7de39b7e1/lib/cidr.rb | 2014 +++++++++++++++++ .../lib/cidr_shortcuts.rb | 401 ++++ .../cache/netaddr-rb-c7a7de39b7e1/lib/eui.rb | 402 ++++ .../netaddr-rb-c7a7de39b7e1/lib/ip_math.rb | 227 ++ .../netaddr-rb-c7a7de39b7e1/lib/methods.rb | 1013 +++++++++ .../netaddr-rb-c7a7de39b7e1/lib/netaddr.rb | 24 + .../cache/netaddr-rb-c7a7de39b7e1/lib/tree.rb | 816 +++++++ .../lib/validation_shortcuts.rb | 201 ++ .../cache/netaddr-rb-c7a7de39b7e1/license | 13 + .../netaddr-rb-c7a7de39b7e1/netaddr.gemspec | 19 + .../netaddr-rb-c7a7de39b7e1/test/cidr_test.rb | 545 +++++ .../netaddr-rb-c7a7de39b7e1/test/eui_test.rb | 101 + .../test/methods_test.rb | 331 +++ .../netaddr-rb-c7a7de39b7e1/test/tree_test.rb | 347 +++ 22 files changed, 6533 insertions(+), 3 deletions(-) delete mode 100644 src/vendor/cache/netaddr-1.5.1.gem create mode 100644 src/vendor/cache/netaddr-rb-c7a7de39b7e1/.bundlecache create mode 100644 src/vendor/cache/netaddr-rb-c7a7de39b7e1/Errors create mode 100644 src/vendor/cache/netaddr-rb-c7a7de39b7e1/README.md create mode 100644 src/vendor/cache/netaddr-rb-c7a7de39b7e1/changelog create mode 100644 src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/cidr.rb create mode 100644 src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/cidr_shortcuts.rb create mode 100644 src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/eui.rb create mode 100644 src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/ip_math.rb create mode 100644 src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/methods.rb create mode 100644 src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/netaddr.rb create mode 100644 src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/tree.rb create mode 100644 src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/validation_shortcuts.rb create mode 100644 src/vendor/cache/netaddr-rb-c7a7de39b7e1/license create mode 100644 src/vendor/cache/netaddr-rb-c7a7de39b7e1/netaddr.gemspec create mode 100644 src/vendor/cache/netaddr-rb-c7a7de39b7e1/test/cidr_test.rb create mode 100644 src/vendor/cache/netaddr-rb-c7a7de39b7e1/test/eui_test.rb create mode 100644 src/vendor/cache/netaddr-rb-c7a7de39b7e1/test/methods_test.rb create mode 100644 src/vendor/cache/netaddr-rb-c7a7de39b7e1/test/tree_test.rb diff --git a/src/Gemfile b/src/Gemfile index b750805084c..1df1d42b0fa 100644 --- a/src/Gemfile +++ b/src/Gemfile @@ -54,6 +54,7 @@ group :development, :test do gem 'rubocop-git' gem 'eventmachine', '~>1.3.0.dev.1', git: 'https://github.com/eventmachine/eventmachine', ref: 'abe34' + gem 'netaddr', '~>1.5.3.dev.1', git: 'https://github.com/dspinhirne/netaddr-rb', tag: '1.5.3' # for director gem 'machinist', '~>1.0' diff --git a/src/Gemfile.lock b/src/Gemfile.lock index 505414c1e21..aa7e5105c0a 100644 --- a/src/Gemfile.lock +++ b/src/Gemfile.lock @@ -1,3 +1,10 @@ +GIT + remote: https://github.com/dspinhirne/netaddr-rb + revision: c7a7de39b7e1126aef11821f98970db18582948b + tag: 1.5.3 + specs: + netaddr (1.5.3) + GIT remote: https://github.com/eventmachine/eventmachine revision: abe347b824e36453f8a013fbe14323342a2ac8de @@ -43,7 +50,7 @@ PATH logging (~> 2.2.2) membrane (~> 1.1.0) nats-pure (~> 0.6.2) - netaddr (~> 1.5.0) + netaddr (~> 1.5.3.dev.1) openssl prometheus-client (~> 1.0.0) puma @@ -175,7 +182,6 @@ GEM mysql2 (0.5.3) nats-pure (0.6.2) net-ssh (5.2.0) - netaddr (1.5.1) netrc (0.11.0) nio4r (2.5.8) openssl (3.0.0) @@ -318,6 +324,7 @@ DEPENDENCIES mysql2 nats-pure (~> 0.6.2) net-ssh + netaddr (~> 1.5.3.dev.1)! openssl parallel_tests (~> 2.0) pg diff --git a/src/bosh-director/bosh-director.gemspec b/src/bosh-director/bosh-director.gemspec index abfb87c301e..8fba6d2e843 100644 --- a/src/bosh-director/bosh-director.gemspec +++ b/src/bosh-director/bosh-director.gemspec @@ -49,7 +49,7 @@ Gem::Specification.new do |spec| spec.add_dependency 'membrane', '~>1.1.0' spec.add_dependency 'nats-pure', '~>0.6.2' spec.add_dependency 'openssl' - spec.add_dependency 'netaddr', '~>1.5.0' + spec.add_dependency 'netaddr', '~>1.5.3.dev.1' spec.add_dependency 'prometheus-client','~>1.0.0' spec.add_dependency 'puma' spec.add_dependency 'rack-test', '~>0.6.2' # needed for console diff --git a/src/vendor/cache/netaddr-1.5.1.gem b/src/vendor/cache/netaddr-1.5.1.gem deleted file mode 100644 index c7d3e4dec1365967cb8ed8efbd5575b73438851b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 41472 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 F{sB#fRP6u& diff --git a/src/vendor/cache/netaddr-rb-c7a7de39b7e1/.bundlecache b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/.bundlecache new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/vendor/cache/netaddr-rb-c7a7de39b7e1/Errors b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/Errors new file mode 100644 index 00000000000..a7342b1e990 --- /dev/null +++ b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/Errors @@ -0,0 +1,7 @@ +=Error Classes + + +-Exception + +-StandardError + +-BoundaryError => CIDR or EUI is out of bounds for a valid address + +-ValidationError => CIDR or EUI failed validation checks + +-VersionError => CIDR or EUI is of improper version for requested operation diff --git a/src/vendor/cache/netaddr-rb-c7a7de39b7e1/README.md b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/README.md new file mode 100644 index 00000000000..c279c44ebd0 --- /dev/null +++ b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/README.md @@ -0,0 +1,9 @@ +# netaddr +I originally created this package back in 2007 out of the need for a tool +which I could use to track an inventory of constantly changing IP subnets. +At the time, I was in the process of migrating away from Perl and towards Ruby +as my primary scripting language. I have since migrated away from using Ruby so +I have not made any major modifications to this code base since 2008 (aside from a +handful of bug fixes that others have pointed out). + +Dustin Spinhirne diff --git a/src/vendor/cache/netaddr-rb-c7a7de39b7e1/changelog b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/changelog new file mode 100644 index 00000000000..ad6c6c7c2ce --- /dev/null +++ b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/changelog @@ -0,0 +1,52 @@ +Version 1.5.2 +Changes: +* bug fixes from: https://github.com/KirillSmirnov, https://github.com/rwhitworth, https://github.com/y13i + +Version 1.5.1 +Changes: +* fixed bug with NetAddr#merge (credit to Daniel Boughton) + + +Version 1.5.0 +Changes: +* fixed bug with EUI48#to_eui64 (credit to Erik Kline) +* fixed bug with u/l bit toggle on EUI#link_local (credit to Erik Kline) +* added EUI#to_ipv6 +* added NetAddr#supernets + + +Version 1.4.0 +Changes: +* Added additional options to NetAddr#sort + + +Version 1.3.0 +New Features: +* added CIDR#[] +* added CIDR#succ (CIDR objects may now be used as args for the standard Ruby Range class) +* added CIDR#allocate_rfc3531 +* added CIDR#to_i +* added CIDRv6.unique_local +* added EUI48#to_eui64 +* added EUI#to_i +* added EUI#to_s + +Changes: +* deprecated 'packed' methods + + +Version 1.2.0 +Changes: +* CIDRv4#new and CIDRv6#new methods have been changed for the sake of speed improvements. + Please use the CIDR#create method instead. +* changes to CIDR#wildcard_mask +* bug fix with validate_eui method +* bug fix with validate_ip_addr +* bug fix and *vast* simplification of NetAddr.merge + + +New Features: +* speed improvements +* added CIDR#set_wildcard_mask +* added <=>, >, <, == methods to CIDR +* NetAddr.merge now reports which CIDR addresses were used to create new summary addresses diff --git a/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/cidr.rb b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/cidr.rb new file mode 100644 index 00000000000..f8248ba142f --- /dev/null +++ b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/cidr.rb @@ -0,0 +1,2014 @@ +module NetAddr + +#=CIDR - Classless Inter-Domain Routing +# +#A class & series of methods for creating and manipulating CIDR network +#addresses. Both IPv4 and IPv6 are supported. +# +#This class accepts a CIDR address, via the CIDR.create method, +#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. +#CIDR.create then creates either a CIDRv4 or CIDRv6 object. An optional tag hash may be +#provided with each CIDR as a way of adding custom labels. +# +#Upon initialization, the IP version is auto-detected and assigned to the +#CIDR. The original IP/Netmask passed within the CIDR is stored and then +#used to determine the confines of the CIDR block. Various properties of the +#CIDR block are accessible via several different methods. There are also +#methods for modifying the CIDR or creating new derivative CIDR's. +# +#An example CIDR object is as follows: +# NetAddr::CIDR.create('192.168.1.20/24') +# +#This would create a CIDR object (192.168.1.0/24) with the following properties: +# version = 4 +# base network = 192.168.1.0 +# ip address = 192.168.1.20 +# netmask = /24 (255.255.255.0) +# size = 256 IP addresses +# broadcast = 192.168.1.255 +# +#You can see how the CIDR object is based around the entire IP space +#defined by the provided IP/Netmask pair, and not necessarily the individual +#IP address itself. +# +class CIDR + +private_class_method :new + + + # IP version 4 or 6. + attr_reader :version + + # Hash of custom tags. Should be in the format tag => value. + attr_reader :tag + + # Integer of either 32 or 128 bits in length, with all bits set to 1 + attr_reader :all_f + + # Integer representing number of bits in this CIDR address + attr_reader :address_len + + # Hash of custom tags. Should be in the format tag => value. + # + # Example: + # cidr4.tag[:name] = 'IPv4 CIDR' + # puts cidr4.tag[:name] + # + def tag=(new_tag) + if (!new_tag.kind_of? Hash) + raise ArgumentError, "Expected Hash, but #{new_tag.class} provided." + end + @tag = new_tag + end + +#===Synopsis +#Create a new CIDRv4 or CIDRv6 object. +#CIDR formatted netmasks take precedence over extended formatted ones. +#CIDR address defaults to a host network (/32 or /128) if netmask not provided. +#:Mask takes precedence over netmask given within CIDR addresses. +#Version will be auto-detected if not specified. +# +# NetAddr::CIDR.create('192.168.1.1/24') +# NetAddr::CIDR.create('192.168.1.1 255.255.255.0') +# NetAddr::CIDR.create(0x0a010001,:Mask => 0xffffff00:Version => 4) +# NetAddr::CIDR.create('192.168.1.1',:WildcardMask => ['0.7.0.255', true]) +# NetAddr::CIDR.create('192.168.1.1',:WildcardMask => [0x000007ff, true] +# NetAddr::CIDR.create('192.168.5.0',:WildcardMask => ['255.248.255.0']) +# NetAddr::CIDR.create('fec0::/64') +# NetAddr::CIDR.create('fec0::/64',:Tag => {'interface' => 'g0/1'}) +# NetAddr::CIDR.create('::ffff:192.168.1.1/96') +# +#===Arguments: +#* addr = CIDR address as a String, or an IP address as an Integer +#* options = Hash with the following keys: +# :Mask -- Integer representing a binary IP Netmask +# :Version -- IP version - Integer +# :Tag -- Custom descriptor tag - Hash, tag => value. +# :WildcardMask -- 2 element Array. First element contains a special bit mask used for +# advanced IP pattern matching. The second element should be set to True if this +# bit mask is bit flipped. +# + def CIDR.create(addr, options=nil) + known_args = [:Mask, :Version, :Tag, :WildcardMask] + ip, netmask, tag = nil, nil, {} + version, wildcard_mask ,wildcard_mask_bit_flipped = nil, nil, false + netmask_int, all_f = nil, nil + + # validate options + if (options) + raise ArgumentError, "Hash expected for argument 'options' but " + + "#{options.class} provided." if (!options.kind_of?(Hash) ) + NetAddr.validate_args(options.keys,known_args) + + if (options.has_key?(:Mask)) + netmask_int = options[:Mask] + raise ArgumentError, "Expected Integer, but #{netmask_int.class} " + + "provided for option :Mask." if (!netmask_int.kind_of?(Integer)) + end + + if (options.has_key?(:Tag)) + tag = options[:Tag] + if (!tag.kind_of? Hash) + raise ArgumentError, "Expected Hash, but #{tag.class} provided for option :Tag." + end + end + + if (options.has_key?(:Version)) + version = options[:Version] + if (version != 4 && version != 6) + raise VersionError, ":Version should be 4 or 6, but was '#{version}'." + end + end + + if (options.has_key?(:WildcardMask)) + if (!options[:WildcardMask].kind_of?(Array)) + raise ArgumentError, "Expected Array, but #{options[:WildcardMask].class} provided for option :WildcardMask." + end + + wildcard_mask = options[:WildcardMask][0] + if (!wildcard_mask.kind_of?(String) && !wildcard_mask.kind_of?(Integer)) + raise ArgumentError, "Expected String or Integer, but #{wildcard_mask.class} provided for wildcard mask." + end + wildcard_mask_bit_flipped = true if (options[:WildcardMask][1] && options[:WildcardMask][1].kind_of?(TrueClass)) + end + end + + # validate addr arg & set version if not provided by user + if (addr.kind_of?(String)) + version = NetAddr.detect_ip_version(addr) if (!version) + + # if extended netmask provided. should only apply to ipv4 + if (version == 4 && addr =~ /.+\s+.+/ ) + addr,netmask = addr.split(' ') + end + + # if netmask part of ip, then separate ip & mask. + if (addr =~ /\//) + ip,netmask = addr.split(/\//) + if (!ip || !netmask) + raise ArgumentError, "CIDR address is improperly formatted. Missing netmask after '/' character." + end + else + ip = addr + end + + NetAddr.validate_ip_str(ip,version) + ip = NetAddr.ip_str_to_int(ip,version) + + elsif (addr.kind_of?(Integer)) + ip = addr + if (!version) + if (ip < 2**32) + version = 4 + else + version = 6 + end + end + NetAddr.validate_ip_int(ip,version) + + else + raise ArgumentError, "String or Integer expected for argument 'addr' but #{addr.class} provided." + end + + # set all_f based on version + all_f = 2**32-1 + all_f = 2**128-1 if (version == 6) + + # set netmask. netmask_int takes precedence. set to all_f if no netmask provided + if (netmask_int) + NetAddr.validate_netmask_int(netmask_int,version,true) + netmask = netmask_int + elsif (netmask) + NetAddr.validate_netmask_str(netmask,version) + netmask = NetAddr.netmask_str_to_int(netmask, version) + else + netmask = all_f + end + + # set wildcard mask if not provided, or validate if provided. + if (wildcard_mask) + begin + if (wildcard_mask.kind_of?(String)) + NetAddr.validate_ip_str(wildcard_mask,version) + wildcard_mask = NetAddr.ip_str_to_int(wildcard_mask, version) + else (wildcard_mask.kind_of?(Integer)) + NetAddr.validate_ip_int(wildcard_mask,version) + end + rescue Exception => error + raise ValidationError, "Provided wildcard mask failed validation: #{error}" + end + end + + return( NetAddr.cidr_build(version, ip, netmask, tag, wildcard_mask, wildcard_mask_bit_flipped) ) + end + +# This method performs absolutely no error checking, and is meant to be used only by +# other internal methods for the sake of the speedier creation of CIDR objects. +# Please consider using #create unless you know what you are doing with 100% certainty. +# +#===Arguments: +#* ip - Integer representing an ip address +#* netmask - Integer representing a binary netmask +#* tag - Hash used to append custom tags to CIDR +#* wildcard_mask - Integer representing a binary mask +#* wildcard_mask_bit_flipped - indicates whether or not the wildcard_mask is bit-flipped or not +# + def initialize(ip, netmask=nil, tag={}, wildcard_mask=nil, wildcard_mask_bit_flipped=false) + @ip = ip + + if ( self.kind_of?(NetAddr::CIDRv4) ) + @version = 4 + @address_len = 32 + else + @version = 6 + @address_len = 128 + end + @all_f = 2**@address_len - 1 + + if (netmask) + @netmask = netmask + else + @netmask = 2**@address_len - 1 + end + + @network = (@ip & @netmask) + @hostmask = @netmask ^ @all_f + @tag = tag + + if (!wildcard_mask) + @wildcard_mask = @netmask + else + @wildcard_mask = wildcard_mask + @wildcard_mask = ~@wildcard_mask if (wildcard_mask_bit_flipped) + end + + end + +#===Synopsis +#Compare the sort order of the current CIDR with a provided CIDR and return true +#if current CIDR is less than provided CIDR. +# +# Example: +# cidr = NetAddr::CIDR.create('192.168.1.0/24') +# cidr < '192.168.2.0/24' => true +# +#===Arguments: +#* CIDR address or NetAddr::CIDR object +# +#===Returns: +#* true or false +# + def <(cidr) + if (!cidr.kind_of?(NetAddr::CIDR)) + begin + cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "Provided argument raised the following " + + "errors: #{error}" + end + end + + if (cidr.version != @version) + raise VersionError, "Attempted to compare a version #{cidr.version} CIDR " + + "with a version #{@version} CIDR." + end + + # compare + lt = false + lt = true if ( NetAddr.cidr_gt_lt(self,cidr) == -1) + + return(lt) + end + +#===Synopsis +#Compare the sort order of the current CIDR with a provided CIDR and return: +#* 1 if the current CIDR is greater than the provided CIDR +#* 0 if the current CIDR and the provided CIDR are equal (base address and netmask are equal) +#* -1 if the current CIDR is less than the provided CIDR +# +# Example: +# cidr = NetAddr::CIDR.create('192.168.1.0/24') +# cidr <=> '192.168.2.0/24' => -1 +# cidr <=> '192.168.0.0/24' => 1 +# cidr <=> '192.168.1.0/24' => 0 +# +#===Arguments: +#* CIDR address or NetAddr::CIDR object +# +#===Returns: +#* Integer +# + def <=>(cidr) + if (!cidr.kind_of?(NetAddr::CIDR)) + begin + cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "Provided argument raised the following " + + "errors: #{error}" + end + end + + if (cidr.version != @version) + raise VersionError, "Attempted to compare a version #{cidr.version} CIDR " + + "with a version #{@version} CIDR." + end + + # compare + comparasin = NetAddr.cidr_gt_lt(self,cidr) + + return(comparasin) + end + +#===Synopsis +#Compare the sort order of the current CIDR with a provided CIDR and return true +#if current CIDR is equal to the provided CIDR. +# +# Example: +# cidr = NetAddr::CIDR.create('192.168.1.0/24') +# cidr == '192.168.1.0/24' => true +# +#===Arguments: +#* CIDR address or NetAddr::CIDR object +# +#===Returns: +#* true or false +# + def ==(cidr) + if (!cidr.kind_of?(NetAddr::CIDR)) + begin + cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "Provided argument raised the following " + + "errors: #{error}" + end + end + + if (cidr.version != @version) + raise VersionError, "Attempted to compare a version #{cidr.version} CIDR " + + "with a version #{@version} CIDR." + end + + # compare + eq = false + eq = true if ( NetAddr.cidr_gt_lt(self,cidr) == 0) + + return(eq) + end + alias :eql? :== + +#===Synopsis +#Compare the sort order of the current CIDR with a provided CIDR and return true +#if current CIDR is greater than provided CIDR. +# +# Example: +# cidr = NetAddr::CIDR.create('192.168.1.0/24') +# cidr > '192.168.0.0/24' => true +# +#===Arguments: +#* CIDR address or NetAddr::CIDR object +# +#===Returns: +#* true or false +# + def >(cidr) + if (!cidr.kind_of?(NetAddr::CIDR)) + begin + cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "Provided argument raised the following " + + "errors: #{error}" + end + end + + if (cidr.version != @version) + raise VersionError, "Attempted to compare a version #{cidr.version} CIDR " + + "with a version #{@version} CIDR." + end + + # compare + gt = false + gt = true if ( NetAddr.cidr_gt_lt(self,cidr) == 1) + + return(gt) + end + +#===Synopsis +#Provide the IP at the given index of the CIDR. +# +# Example: +# cidr4 = NetAddr::CIDR.create('192.168.1.0/24') +# cidr4[1] => 192.168.1.1/32 +# +#===Arguments: +#* index = Index number as an Integer +# +#===Returns: +#* NetAddr::CIDR object. +# + def [](index) + raise ArgumentError, "Integer expected for argument 'index' but " + + "#{index.class} provided." if (!index.kind_of?(Integer) ) + + addr = @network + index + if ( (@hostmask | addr) == (@hostmask | @network) ) + addr = NetAddr.cidr_build(@version, addr) + else + raise BoundaryError, "Index of #{index} returns IP that is out of " + + "bounds of CIDR network." + end + + return(addr) + end + +#===Synopsis +#RFC 3531 describes a flexible method for IP subnet allocation from +#a larger parent network. Given the new netmask for subnet allocations from this CIDR, +#provide a list of those subnets arranged by the order in which they should be allocated. +# +# Example: +# cidr = NetAddr::CIDR.create('192.168.0.0/16') +# cidr.allocate_rfc3531(21, :Strategy => :centermost) => ["192.168.0.0/21"... "192.168.248.0/21"] +# +#===Arguments: +#* netmask (in bits) for all new subnet allocations +#* options = Hash with the following keys: +# :Objectify -- if true, return NetAddr::CIDR objects +# :Short -- if true, return IPv6 addresses in short-hand notation +# :Strategy -- allocation strategy to use. must be either :centermost or :leftmost (default) +# +#===Returns: +#* Array of Strings or CIDR objects +# + def allocate_rfc3531(netmask, options=nil) + short = false + objectify = false + strategy = :leftmost + + # validate args + raise ArgumentError, "Expected Integer for argument (netmask), but #{max.class} received." if ( !netmask.kind_of?(Integer) ) + raise BoundaryError, "Netmask (#{netmask}) is invalid for a version #{self.version} address." if (netmask > @address_len) + raise BoundaryError, "Netmask (#{netmask}) cannot be less than #{self.bits}." if (netmask < self.bits) + known_args = [:Objectify, :Short, :Strategy] + if (options) + if (!options.kind_of? Hash) + raise ArgumentError, "Expected Hash, but #{options.class} provided." + end + NetAddr.validate_args(options.keys,known_args) + + if( options.has_key?(:Objectify) && options[:Objectify] == true ) + objectify = true + end + + if( options.has_key?(:Short) && options[:Short] == true ) + short = true + end + + if( options.has_key?(:Strategy)) + strategy = options[:Strategy] + raise ArgumentError, "Argument :Strategy must be either :leftmost or :centermost." if (strategy != :leftmost && strategy != :centermost) + end + end + + subnet_bits = netmask - self.bits + net_lshift = @address_len - netmask + new_mask = NetAddr.bits_to_mask(netmask,self.version) + cidr_list = [] + if (strategy == :leftmost) + (0..(2**subnet_bits)-1).each do |num| + mirror = NetAddr.binary_mirror(num, subnet_bits) + + if (!objectify) + my_ip_s = NetAddr.ip_int_to_str(@network | (mirror << net_lshift), @version) + my_ip_s = NetAddr.shorten(my_ip_s) if (short && @version == 6) + cidr_list.push( my_ip_s << '/' << netmask.to_s ) + else + cidr_list.push( NetAddr.cidr_build(@version, @network | (mirror << net_lshift), new_mask ) ) + end + end + + else # :centermost + round = 1 + bit_count = 1 + lshift = subnet_bits/2 + lshift -= 1 if (subnet_bits & 1 == 0) # if subnet_bits is even number + + unique = {} + until (bit_count > subnet_bits) + (0..2**bit_count-1).each do |num| + shifted = num << lshift + if ( !unique.has_key?(shifted) ) + if (!objectify) + my_ip_s = NetAddr.ip_int_to_str(@network | (shifted << net_lshift), @version) + my_ip_s = NetAddr.shorten(my_ip_s) if (short && @version == 6) + cidr_list.push( my_ip_s << '/' << netmask.to_s ) + else + cidr_list.push( NetAddr.cidr_build(@version, @network | (shifted << net_lshift), new_mask ) ) + end + unique[shifted] = true + end + end + + lshift -= 1 if (round & 1 == 0) # if even round + round += 1 + bit_count += 1 + end + end + + return(cidr_list) + end + +#===Synopsis +#Depending on the IP version of the current CIDR, +#return either an in-addr.arpa. or ip6.arpa. string. The netmask will be used +#to determine the length of the returned string. +# Example: +# cidr = NetAddr::CIDR.create('192.168.1.1/24') +# cidr.arpa => "1.168.192.in-addr.arpa." +# +#===Arguments: +#* none +# +#===Returns: +#* String +# + def arpa() + + base = self.ip() + netmask = self.bits() + + if (@version == 4) + net = base.split('.') + + if (netmask) + while (netmask < 32) + net.pop + netmask = netmask + 8 + end + end + + arpa = net.reverse.join('.') + arpa << ".in-addr.arpa." + + elsif (@version == 6) + fields = base.split(':') + net = [] + fields.each do |field| + (field.split("")).each do |x| + net.push(x) + end + end + + if (netmask) + while (netmask < 128) + net.pop + netmask = netmask + 4 + end + end + + arpa = net.reverse.join('.') + arpa << ".ip6.arpa." + + end + + return(arpa) + end + +#===Synopsis +#Provide number of bits in Netmask. +# Example: +# cidr = NetAddr::CIDR.create('192.168.1.1/24') +# cidr.bits => 24 +# +#===Arguments: +#* none +# +#===Returns: +#* Integer. +# + def bits() + return(NetAddr.mask_to_bits(@netmask)) + end + +#===Synopsis +#Compare the current CIDR with a provided CIDR and return: +#* 1 if the current CIDR contains (is supernet of) the provided CIDR +#* 0 if the current CIDR and the provided CIDR are equal (base address and netmask are equal) +#* -1 if the current CIDR is contained by (is subnet of) the provided CIDR +#* nil if the two CIDR addresses are unrelated +# +# Example: +# cidr = NetAddr::CIDR.create('192.168.1.0/24') +# cidr.cmp('192.168.1.0/25') => 1 +# cidr.cmp('192.168.1.0/24') => 0 +# cidr.cmp('192.168.0.0/23') => -1 +# cidr.cmp('10.0.0.0/24') => nil +# +#===Arguments: +#* CIDR address or NetAddr::CIDR object +# +#===Returns: +#* Integer or nil +# + def cmp(cidr) + if (!cidr.kind_of?(NetAddr::CIDR)) + begin + cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "Provided argument raised the following " + + "errors: #{error}" + end + end + + if (cidr.version != @version) + raise VersionError, "Attempted to compare a version #{cidr.version} CIDR " + + "with a version #{@version} CIDR." + end + + # compare + comparasin = NetAddr.cidr_compare(self,cidr) + + return(comparasin) +end + +#===Synopsis +#Determines if this CIDR contains (is supernet of) +#the provided CIDR address or NetAddr::CIDR object. +# +# Example: +# cidr4 = NetAddr::CIDR.create('192.168.1.0/24') +# cidr6 = NetAddr::CIDR.create('fec0::/64') +# cidr6_2 = NetAddr::CIDR.create('fec0::/96') +# cidr4.contains?('192.168.1.2') => true +# cidr6.contains?(cidr6_2) => true +# +#===Arguments: +#* cidr = CIDR address or NetAddr::CIDR object +# +#===Returns: +#* true or false +# + def contains?(cidr) + contains = false + + if (!cidr.kind_of?(NetAddr::CIDR)) + begin + cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "Provided argument raised the following " + + "errors: #{error}" + end + end + + if (cidr.version != @version) + raise VersionError, "Attempted to compare a version #{cidr.version} CIDR " + + "with a version #{@version} CIDR." + end + + contains = true if ( NetAddr.cidr_compare(self,cidr) == 1 ) + + return(contains) + end + +#===Synopsis +#See to_s +# + def desc(options=nil) + to_s(options) + end + +#===Synopsis +#Provide all IP addresses contained within the IP space of this CIDR. +# +# Example: +# cidr4 = NetAddr::CIDR.create('192.168.1.1/24') +# cidr6 = NetAddr::CIDR.create('fec0::/64') +# cidr4.enumerate(:Limit => 4, :Bitstep => 32) +# cidr6.enumerate(:Limit => 4, :Bitstep => 32, :Objectify => true) +# +#===Arguments: +#* options = Hash with the following keys: +# :Bitstep -- enumerate in X sized steps - Integer +# :Limit -- limit returned list to X number of items - Integer +# :Objectify -- if true, return NetAddr::CIDR objects +# :Short -- if true, return IPv6 addresses in short-hand notation +# +#===Returns: +#* Array of Strings, or Array of NetAddr::CIDR objects +# + def enumerate(options=nil) + known_args = [:Bitstep, :Limit, :Objectify, :Short] + bitstep = 1 + objectify = false + limit = nil + short = false + + if (options) + if (!options.kind_of? Hash) + raise ArgumentError, "Expected Hash, but #{options.class} provided." + end + NetAddr.validate_args(options.keys,known_args) + + if( options.has_key?(:Bitstep) ) + bitstep = options[:Bitstep] + end + + if( options.has_key?(:Objectify) && options[:Objectify] == true ) + objectify = true + end + + if( options.has_key?(:Limit) ) + limit = options[:Limit] + end + + if( options.has_key?(:Short) && options[:Short] == true ) + short = true + end + end + + list = [] + my_ip = @network + change_mask = @hostmask | my_ip + + until ( change_mask != (@hostmask | @network) ) + if (!objectify) + my_ip_s = NetAddr.ip_int_to_str(my_ip, @version) + my_ip_s = NetAddr.shorten(my_ip_s) if (short && @version == 6) + list.push( my_ip_s ) + else + list.push( NetAddr.cidr_build(@version,my_ip) ) + end + my_ip = my_ip + bitstep + change_mask = @hostmask | my_ip + if (limit) + limit = limit - 1 + break if (limit == 0) + end + end + + return(list) + end + +#===Synopsis +#Given a list of subnets of the current CIDR, return a new list with any +#holes (missing subnets) filled in. +# +# Example: +# cidr4 = NetAddr::CIDR.create('192.168.1.0/24') +# cidr4.fill_in(['192.168.1.0/27','192.168.1.64/26','192.168.1.128/25']) +# +#===Arguments: +#* list = Array of CIDR addresses, or Array of NetAddr::CIDR objects +#* options = Hash with the following keys: +# :Objectify -- if true, return NetAddr::CIDR objects +# :Short -- if true, return IPv6 addresses in short-hand notation +# +#===Returns: +#* Array of CIDR Strings, or an Array of NetAddr::CIDR objects +# + + def fill_in(list, options=nil) + known_args = [:Objectify, :Short] + short = false + objectify = false + + # validate list + raise ArgumentError, "Array expected for argument 'list' but #{list.class} provided." if (!list.kind_of?(Array) ) + + # validate options + if (options) + raise ArgumentError, "Hash expected for argument 'options' but " + + "#{options.class} provided." if (!options.kind_of?(Hash) ) + NetAddr.validate_args(options.keys,known_args) + + if (options.has_key?(:Short) && options[:Short] == true) + short = true + end + + if (options.has_key?(:Objectify) && options[:Objectify] == true) + objectify = true + end + end + + # validate each cidr and store in cidr_list + cidr_list = [] + list.each do |obj| + if (!obj.kind_of?(NetAddr::CIDR)) + begin + obj = NetAddr::CIDR.create(obj) + rescue Exception => error + aise ArgumentError, "A provided CIDR raised the following " + + "errors: #{error}" + end + end + + if (!obj.version == self.version) + raise VersionError, "#{obj.desc(:Short => true)} is not a version #{self.version} address." + end + + # make sure we contain the cidr + if ( self.contains?(obj) == false ) + raise "#{obj.desc(:Short => true)} does not fit " + + "within the bounds of #{self.desc(:Short => true)}." + end + cidr_list.push(obj) + end + + complete_list = NetAddr.cidr_fill_in(self,cidr_list) + if (!objectify) + subnets = [] + complete_list.each {|entry| subnets.push(entry.desc(:Short => short))} + return(subnets) + else + return(complete_list) + end + end + +#===Synopsis +#Provide original IP address passed during initialization. +# +# Example: +# cidr = NetAddr::CIDR.create('192.168.1.1/24') +# cidr.ip => "192.168.1.1" +# +#===Arguments: +#* options = Hash with the following keys: +# :Objectify -- if true, return NetAddr::CIDR object +# :Short -- if true, return IPv6 addresses in short-hand notation +# +#===Returns: +#* String or NetAddr::CIDR object. +# + def ip(options=nil) + known_args = [:Objectify, :Short] + objectify = false + short = false + + if (options) + if (!options.kind_of?(Hash)) + raise ArgumentError, "Expected Hash, but " + + "#{options.class} provided." + end + NetAddr.validate_args(options.keys,known_args) + + if( options.has_key?(:Short) && options[:Short] == true ) + short = true + end + + if( options.has_key?(:Objectify) && options[:Objectify] == true ) + objectify = true + end + end + + + if (!objectify) + ip = NetAddr.ip_int_to_str(@ip, @version) + ip = NetAddr.shorten(ip) if (short && @version == 6) + else + ip = NetAddr.cidr_build(@version,@ip) + end + + return(ip) + end + +#===Synopsis +#Determines if this CIDR is contained within (is subnet of) +#the provided CIDR address or NetAddr::CIDR object. +# +# Example: +# cidr4 = NetAddr::CIDR.create('192.168.1.1/24') +# cidr4.is_contained?('192.168.0.0/23') +# +#===Arguments: +#* cidr = CIDR address or NetAddr::CIDR object +# +#===Returns: +#* true or false +# + def is_contained?(cidr) + is_contained = false + + if (!cidr.kind_of?(NetAddr::CIDR)) + begin + cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "Provided argument raised the following " + + "errors: #{error}" + end + end + + if (cidr.version != @version) + raise VersionError, "Attempted to compare a version #{cidr.version} CIDR " + + "with a version #{@version} CIDR." + end + + network = cidr.to_i(:network) + netmask = cidr.to_i(:netmask) + hostmask = cidr.to_i(:hostmask) + + is_contained = true if ( NetAddr.cidr_compare(self,cidr) == -1 ) + + return(is_contained) + end + +#===Synopsis +#Provide last IP address in this CIDR object. +# +# Example: +# cidr = NetAddr::CIDR.create('192.168.1.0/24') +# cidr.last => "192.168.1.255" +# +#===Arguments: +#* options = Hash with the following keys: +# :Objectify -- if true, return NetAddr::CIDR object +# :Short -- if true, return IPv6 addresses in short-hand notation +# +#===Returns: +#* String or NetAddr::CIDR object. +# + def last(options=nil) + known_args = [:Objectify, :Short] + objectify = false + short = false + + if (options) + if (!options.kind_of?(Hash)) + raise ArgumentError, "Expected Hash, but " + + "#{options.class} provided." + end + NetAddr.validate_args(options.keys,known_args) + + if( options.has_key?(:Short) && options[:Short] == true ) + short = true + end + + if( options.has_key?(:Objectify) && options[:Objectify] == true ) + objectify = true + end + + end + + ip_int = @network | @hostmask + if (!objectify) + ip = NetAddr.ip_int_to_str(ip_int, @version) + ip = NetAddr.shorten(ip) if (short && !objectify && @version == 6) + else + ip = NetAddr.cidr_build(@version,ip_int) + end + + return(ip) + end + +#===Synopsis +#Given an IP address (or if a NetAddr::CIDR object, then the original IP of that object), determine +#if it falls within the range of addresses resulting from the combination of the +#IP and Wildcard Mask of this CIDR. +# +# Example: +# cidr4 = NetAddr.CIDRv4.create('10.0.0.0', :WildcardMask => ['0.7.0.255', true]) +# cidr4.matches?('10.0.0.22') -> true +# cidr4.matches?('10.8.0.1') -> false +# cidr4.matches?('10.1.0.1') -> true +# cidr4.matches?('10.0.1.22') -> false +# +#===Arguments: +#* ip = IP address as a String or a CIDR object +# +#===Returns: +#* True or False +# + def matches?(ip) + ip_int = nil + if (!ip.kind_of?(NetAddr::CIDR)) + begin + ip_int = NetAddr.ip_to_i(ip, :Version => @version) + rescue NetAddr::ValidationError + raise NetAddr::ValidationError, "Provided IP must be a valid IPv#{@version} address." + end + else + raise NetAddr::ValidationError, "Provided CIDR must be of type #{self.class}" if (ip.class != self.class) + ip_int = ip.to_i(:ip) + end + + return(true) if (@ip & @wildcard_mask == ip_int & @wildcard_mask) + return(false) + end + +#===Synopsis +#Assuming this CIDR is a valid multicast address (224.0.0.0/4 for IPv4 +#and ff00::/8 for IPv6), return its ethernet MAC address (EUI-48) mapping. +#MAC address is based on original IP address passed during initialization. +# +# Example: +# mcast = NetAddr::CIDR.create('224.0.0.6') +# mcast.multicast_mac.address +# +#===Arguments: +#* options = Hash with the following keys: +# :Objectify -- if true, return EUI objects +# +#===Returns: +#* String or NetAddr::EUI48 object +# + def multicast_mac(options=nil) + known_args = [:Objectify] + objectify = false + + if (options) + if (!options.kind_of? Hash) + raise ArgumentError, "Expected Hash, but #{options.class} provided." + end + NetAddr.validate_args(options.keys,known_args) + + if (options.has_key?(:Objectify) && options[:Objectify] == true) + objectify = true + end + end + + if (@version == 4) + if (@ip & 0xf0000000 == 0xe0000000) + # map low order 23-bits of ip to 01:00:5e:00:00:00 + mac = @ip & 0x007fffff | 0x01005e000000 + else + raise ValidationError, "#{self.ip} is not a valid multicast address. IPv4 multicast " + + "addresses should be in the range 224.0.0.0/4." + end + else + if (@ip & (0xff << 120) == 0xff << 120) + # map low order 32-bits of ip to 33:33:00:00:00:00 + mac = @ip & (2**32-1) | 0x333300000000 + else + raise ValidationError, "#{self.ip} is not a valid multicast address. IPv6 multicast " + + "addresses should be in the range ff00::/8." + end + end + + eui = NetAddr::EUI48.new(mac) + eui = eui.address if (!objectify) + + return(eui) + end + +#===Synopsis +#Provide netmask in CIDR format (/yy). +# +# Example: +# cidr = NetAddr::CIDR.create('192.168.1.0/24') +# cidr.netmask => "/24" +# +#===Arguments: +#* none +# +#===Returns: +#* String +# + def netmask() + bits = NetAddr.mask_to_bits(@netmask) + return("/#{bits}") + end + +#===Synopsis +#Provide base network address. +# +# Example: +# cidr = NetAddr::CIDR.create('192.168.1.0/24') +# cidr.network => "192.168.1.0" +# +#===Arguments: +#* options = Hash with the following fields: +# :Objectify -- if true, return NetAddr::CIDR object +# :Short -- if true, return IPv6 addresses in short-hand notation +# +#===Returns: +#* String or NetAddr::CIDR object. +# + def network(options=nil) + known_args = [:Objectify, :Short] + objectify = false + short = false + + if (options) + if (!options.kind_of?(Hash)) + raise ArgumentError, "Expected Hash, but " + + "#{options.class} provided." + end + NetAddr.validate_args(options.keys,known_args) + + if( options.has_key?(:Short) && options[:Short] == true ) + short = true + end + + if( options.has_key?(:Objectify) && options[:Objectify] == true ) + objectify = true + end + end + + + if (!objectify) + ip = NetAddr.ip_int_to_str(@network, @version) + ip = NetAddr.shorten(ip) if (short && @version == 6) + else + ip = NetAddr.cidr_build(@version,@network) + end + + return(ip) + end + + alias :base :network + alias :first :network + +#===Synopsis +#Provide the next IP following the last available IP within this CIDR object. +# +# Example: +# cidr4 = NetAddr::CIDR.create('192.168.1.1/24') +# cidr6 = NetAddr::CIDR.create('fec0::/64') +# cidr4.next_subnet() +# cidr6.next_subnet(:Short => true)} +# +#===Arguments: +#* options = Hash with the following keys: +# :Bitstep -- step in X sized steps - Integer +# :Objectify -- if true, return NetAddr::CIDR object +# :Short -- if true, return IPv6 addresses in short-hand notation +# +#===Returns: +#* String or NetAddr::CIDR object. +# + def next_ip(options=nil) + known_args = [:Bitstep, :Objectify, :Short] + bitstep = 1 + objectify = false + short = false + + if (options) + if (!options.kind_of?(Hash)) + raise ArgumentError, "Expected Hash, but " + + "#{options.class} provided." + end + NetAddr.validate_args(options.keys,known_args) + + if( options.has_key?(:Bitstep) ) + bitstep = options[:Bitstep] + end + + if( options.has_key?(:Short) && options[:Short] == true ) + short = true + end + + if( options.has_key?(:Objectify) && options[:Objectify] == true ) + objectify = true + end + end + + next_ip = @network + @hostmask + bitstep + + if (next_ip > @all_f) + raise BoundaryError, "Returned IP is out of bounds for IPv#{@version}." + end + + + if (!objectify) + next_ip = NetAddr.ip_int_to_str(next_ip, @version) + next_ip = NetAddr.shorten(next_ip) if (short && @version == 6) + else + next_ip = NetAddr.cidr_build(@version,next_ip) + end + + return(next_ip) + end + +#===Synopsis +#Provide the next subnet following this CIDR object. The next subnet will +#be of the same size as the current CIDR object. +# +# Example: +# cidr4 = NetAddr::CIDR.create('192.168.1.1/24') +# cidr6 = NetAddr::CIDR.create('fec0::/64') +# cidr4.next_subnet() +# cidr6.next_subnet(:Short => true) +# +#===Arguments: +#* options = Hash with the following keys: +# :Bitstep -- step in X sized steps. - Integer +# :Objectify -- if true, return NetAddr::CIDR object +# :Short -- if true, return IPv6 addresses in short-hand notation +# +#===Returns: +#* String or NetAddr::CIDR object. +# + def next_subnet(options=nil) + known_args = [:Bitstep, :Objectify, :Short] + bitstep = 1 + objectify = false + short = false + + if (options) + if (!options.kind_of?(Hash)) + raise ArgumentError, "Expected Hash, but " + + "#{options.class} provided." + end + NetAddr.validate_args(options.keys,known_args) + + if( options.has_key?(:Bitstep) ) + bitstep = options[:Bitstep] + end + + if( options.has_key?(:Short) && options[:Short] == true ) + short = true + end + + if( options.has_key?(:Objectify) && options[:Objectify] == true ) + objectify = true + end + end + + bitstep = bitstep * (2**(@address_len - self.bits) ) + next_sub = @network + bitstep + + if (next_sub > @all_f) + raise BoundaryError, "Returned subnet is out of bounds for IPv#{@version}." + end + + if (!objectify) + next_sub = NetAddr.ip_int_to_str(next_sub, @version) + next_sub = NetAddr.shorten(next_sub) if (short && @version == 6) + next_sub = next_sub << "/" << self.bits.to_s + else + next_sub = NetAddr.cidr_build(@version,next_sub,self.to_i(:netmask)) + end + + return(next_sub) + end + +#===Synopsis +#Provide the nth IP within this object. +# +# Example: +# cidr4 = NetAddr::CIDR.create('192.168.1.1/24') +# cidr4.nth(1) +# cidr4.nth(1, :Objectify => true) +# +#===Arguments: +#* index = Index number as an Integer +#* options = Hash with the following keys: +# :Objectify -- if true, return NetAddr::CIDR objects +# :Short -- if true, return IPv6 addresses in short-hand notation +# +#===Returns: +#* String or NetAddr::CIDR object. +# + def nth(index, options=nil) + known_args = [:Objectify, :Short] + objectify = false + short = false + + # validate list + raise ArgumentError, "Integer expected for argument 'index' but " + + "#{index.class} provided." if (!index.kind_of?(Integer) ) + + # validate options + if (options) + raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash) ) + NetAddr.validate_args(options.keys,known_args) + + if( options.has_key?(:Short) && options[:Short] == true ) + short = true + end + + if( options.has_key?(:Objectify) && options[:Objectify] == true ) + objectify = true + end + end + + my_ip = @network + index + if ( (@hostmask | my_ip) == (@hostmask | @network) ) + + if (!objectify) + my_ip = NetAddr.ip_int_to_str(my_ip, @version) + my_ip = NetAddr.shorten(my_ip) if (short && @version == 6) + else + my_ip = NetAddr.cidr_build(@version,my_ip) + end + + else + raise BoundaryError, "Index of #{index} returns IP that is out of " + + "bounds of CIDR network." + end + + return(my_ip) + end + +#===Synopsis +#Given a set of index numbers for this CIDR, return all IP addresses within the +#CIDR that are between them (inclusive). If an upper bound is not provided, then +#all addresses from the lower bound up will be returned. +# +# Example: +# cidr4 = NetAddr::CIDR.create('192.168.1.1/24') +# cidr4.range(0, 1) +# cidr4.range(0, 1, :Objectify => true) +# cidr4.range(0, nil, :Objectify => true) +# +#===Arguments: +#* lower = Lower range boundary index as an Integer +#* upper = Upper range boundary index as an Integer +#* options = Hash with the following keys: +# :Bitstep -- enumerate in X sized steps - Integer +# :Objectify -- if true, return NetAddr::CIDR objects +# :Short -- if true, return IPv6 addresses in short-hand notation +# +#===Returns: +#* Array of Strings, or Array of NetAddr::CIDR objects +# +#===Note: +#If you do not need all of the fancy options in this method, then please consider +#using the standard Ruby Range class as shown below. +# +# Example: +# start = NetAddr::CIDR.create('192.168.1.0') +# fin = NetAddr::CIDR.create('192.168.2.3') +# (start..fin).each {|addr| puts addr.desc} +# + def range(lower, upper=nil, options=nil) + known_args = [:Bitstep, :Objectify, :Short] + objectify = false + short = false + bitstep = 1 + + # validate indexes + raise ArgumentError, "Integer expected for argument 'lower' " + + "but #{lower.class} provided." if (!lower.kind_of?(Integer)) + + raise ArgumentError, "Integer expected for argument 'upper' " + + "but #{upper.class} provided." if (upper && !upper.kind_of?(Integer)) + + upper = @hostmask if (upper.nil?) + indexes = [lower,upper] + indexes.sort! + if ( (indexes[0] < 0) || (indexes[0] > self.size) ) + raise BoundaryError, "Index #{indexes[0]} is out of bounds for this CIDR." + end + + if (indexes[1] >= self.size) + raise BoundaryError, "Index #{indexes[1]} is out of bounds for this CIDR." + end + + # validate options + if (options) + raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash) ) + NetAddr.validate_args(options.keys,known_args) + + if( options.has_key?(:Short) && options[:Short] == true ) + short = true + end + + if( options.has_key?(:Objectify) && options[:Objectify] == true ) + objectify = true + end + + if( options.has_key?(:Bitstep) ) + bitstep = options[:Bitstep] + end + end + + # make range + start_ip = @network + indexes[0] + end_ip = @network + indexes[1] + my_ip = start_ip + list = [] + until (my_ip > end_ip) + if (!objectify) + ip = NetAddr.ip_int_to_str(my_ip, @version) + ip = NetAddr.shorten(ip) if (short && @version == 6) + else + ip = NetAddr.cidr_build(@version,my_ip) + end + + list.push(ip) + my_ip += bitstep + end + + return(list) + end + +#===Synopsis +#Given a single subnet of the current CIDR, provide the remainder of +#the subnets. For example if the original CIDR is 192.168.0.0/24 and you +#provide 192.168.0.64/26 as the portion to exclude, then 192.168.0.0/26, +#and 192.168.0.128/25 will be returned as the remainders. +# +# cidr4 = NetAddr::CIDR.create('192.168.1.0/24') +# cidr4.remainder('192.168.1.32/27') +# cidr4.remainder('192.168.1.32/27', :Objectify => true) +# +#===Arguments: +#* addr = CIDR address or NetAddr::CIDR object +#* options = Hash with the following keys: +# :Objectify -- if true, return NetAddr::CIDR objects +# :Short -- if true, return IPv6 addresses in short-hand notation +# +#===Returns: +#* Array of Strings, or Array of NetAddr::CIDR objects +# + def remainder(addr, options=nil) + known_args = [:Objectify, :Short] + short = nil + objectify = nil + + # validate options + if (options) + raise ArgumentError, "Hash expected for argument 'options' but " + + "#{options.class} provided." if (!options.kind_of?(Hash) ) + NetAddr.validate_args(options.keys,known_args) + + if( options.has_key?(:Short) && options[:Short] == true ) + short = true + end + + if( options.has_key?(:Objectify) && options[:Objectify] == true ) + objectify = true + end + end + + if ( !addr.kind_of?(NetAddr::CIDR) ) + begin + addr = NetAddr::CIDR.create(addr) + rescue Exception => error + raise ArgumentError, "Argument 'addr' raised the following " + + "errors: #{error}" + end + end + + + # make sure 'addr' is the same ip version + if ( addr.version != @version ) + raise VersionError, "#{addr.desc(:Short => true)} is of a different " + + "IP version than #{self.desc(:Short => true)}." + end + + # make sure we contain 'to_exclude' + if ( self.contains?(addr) != true ) + raise BoundaryError, "#{addr.desc(:Short => true)} does not fit " + + "within the bounds of #{self.desc(:Short => true)}." + end + + # split this cidr in half & see which half 'to_exclude' + # belongs in. take that half & repeat the process. every time + # we repeat, store the non-matching half + new_mask = self.bits + 1 + lower_network = self.to_i(:network) + upper_network = self.to_i(:network) + 2**(@address_len - new_mask) + + new_subnets = [] + until(new_mask > addr.bits) + if (addr.to_i(:network) < upper_network) + match = lower_network + non_match = upper_network + else + match = upper_network + non_match = lower_network + end + + if (!objectify) + non_match = NetAddr.ip_int_to_str(non_match, @version) + non_match = NetAddr.shorten(non_match) if (short && @version == 6) + new_subnets.unshift("#{non_match}/#{new_mask}") + else + new_subnets.unshift( NetAddr.cidr_build(@version, non_match, NetAddr.bits_to_mask(new_mask,version) ) ) + end + + new_mask = new_mask + 1 + lower_network = match + upper_network = match + 2**(@address_len - new_mask) + end + + return(new_subnets) + end + +#===Synopsis +#Resize the CIDR by changing the size of the Netmask. +#Return the resulting CIDR as a new object. +# +# Example: +# cidr4 = NetAddr::CIDR.create('192.168.1.1/24') +# new_cidr = cidr4.resize(23) +# +#===Arguments: +#* bits = Netmask as an Integer +# +#===Returns: +#* NetAddr::CIDR object +# + def resize(bits) + raise ArgumentError, "Integer or Hash expected, but " + + "#{bits.class} provided." if (!bits.kind_of?(Integer)) + + NetAddr.validate_ip_netmask(bits, :Version => @version) + netmask = NetAddr.bits_to_mask(bits, @version) + network = @network & netmask + + return( NetAddr.cidr_build(@version, network, netmask) ) + end + +#===Synopsis +#Resize the current CIDR by changing the size of the Netmask. The original IP +#passed during initialization will be set to the base network address if +#it no longer falls within the bounds of the CIDR. +# +# Example: +# cidr4 = NetAddr::CIDR.create('192.168.1.1/24') +# cidr4.resize!(23) +# +#===Arguments: +#* bits = Netmask as an Integer +# +#===Returns: +#* True +# + def resize!(bits) + raise ArgumentError, "Integer or Hash expected, but " + + "#{bits.class} provided." if (!bits.kind_of?(Integer)) + + NetAddr.validate_ip_netmask(bits, :Version => @version) + netmask = NetAddr.netmask_to_i(bits, :Version => @version) + + @netmask = netmask + @network = @network & netmask + @hostmask = @netmask ^ @all_f + + # check @ip + if ((@ip & @netmask) != (@network)) + @ip = @network + end + + return(true) + end + +#===Synopsis +#Set the wildcard mask. Wildcard masks are typically used for matching +#entries in an access-list. +# +# Example: +# cidr4 = NetAddr::CIDR.create('192.168.1.0/24') +# cidr4.set_wildcard_mask('0.0.0.255', true) +# cidr4.set_wildcard_mask('255.255.255.0') +# +#===Arguments: +#* mask = wildcard mask as a String or Integer +#* bit_flipped = if set True then the wildcard mask is interpereted as bit-flipped. +# +#===Returns: +#* nil +# + def set_wildcard_mask(mask, bit_flipped=false) + netmask_int = nil + if (mask.kind_of?(Integer)) + NetAddr.validate_ip_int(mask,@version) + netmask_int = mask + else + begin + NetAddr.validate_ip_str(mask,@version) + netmask_int = NetAddr.ip_str_to_int(mask, @version) + rescue NetAddr::ValidationError + raise NetAddr::ValidationError, "Wildcard Mask must be a valid IPv#{@version} address." + end + end + netmask_int = ~netmask_int if (bit_flipped) + @wildcard_mask = netmask_int + + return(nil) + end + +#===Synopsis +#Provide number of IP addresses within this CIDR. +# +# Example: +# cidr = NetAddr::CIDR.create('192.168.1.0/24') +# cidr.size => 256 +# +#===Arguments: +#* none +# +#===Returns: +#* Integer +# + def size() + return(@hostmask + 1) + end + +#===Synopsis +#Create subnets for this CIDR. There are 2 ways to create subnets: +# * By providing the netmask (in bits) of the new subnets with :Bits. +# * By providing the number of IP addresses needed in the new subnets with :IPCount +# +#:NumSubnets is used to determine how the CIDR is subnetted. For example, if I request +#the following operation: +# +# NetAddr::CIDR.create('192.168.1.0/24').subnet(:Bits => 26, :NumSubnets => 1) +# +#then I would get back the first /26 subnet of 192.168.1.0/24 and the remainder of the IP +#space as summary CIDR addresses (e.g. 192.168.1.0/26, 192.168.1.64/26, and 192.168.1.128/25). +#If I were to perform the same operation without the :NumSubnets directive, then 192.168.1.0/24 +#will be fully subnetted into X number of /26 subnets (e.g. 192.168.1.0/26, 192.168.1.64/26, +#192.168.1.128/26, and 192.168.1.192/26). +# +#If neither :Bits nor :IPCount is provided, then the current CIDR will be split in half. +#If both :Bits and :IPCount are provided, then :Bits takes precedence. +# +# Example: +# cidr4 = NetAddr::CIDR.create('192.168.1.0/24') +# cidr6 = NetAddr::CIDR.create('fec0::/64') +# cidr4.subnet(:Bits => 28, :NumSubnets => 3) +# cidr4.subnet(:IPCount => 19) +# cidr4.subnet(:Bits => 28) +# cidr6.subnet(:Bits => 67, :NumSubnets => 4, :Short => true) +# +#===Arguments: +#* options = Hash with the following keys: +# :Bits -- Netmask (in bits) of new subnets - Integer +# :IPCount -- Minimum number of IP's that new subnets should contain - Integer +# :NumSubnets -- Number of X sized subnets to return - Integer +# :Objectify -- if true, return NetAddr::CIDR objects +# :Short -- if true, return IPv6 addresses in short-hand notation +# +#===Returns: +#* Array of Strings, or Array of NetAddr::CIDR objects +# + def subnet(options=nil) + known_args = [:Bits, :IPCount, :NumSubnets, :Objectify, :Short] + my_network = self.to_i(:network) + my_mask = self.bits + subnet_bits = my_mask + 1 + min_count = nil + objectify = false + short = false + + if (options) + if (!options.kind_of? Hash) + raise ArgumentError, "Expected Hash, but #{options.class} provided." + end + NetAddr.validate_args(options.keys,known_args) + + if ( options.has_key?(:IPCount) ) + subnet_bits = NetAddr.ip_count_to_size(options[:IPCount], @version) + end + + if ( options.has_key?(:Bits) ) + subnet_bits = options[:Bits] + end + + if ( options.has_key?(:NumSubnets) ) + num_subnets = options[:NumSubnets] + end + + if( options.has_key?(:Short) && options[:Short] == true ) + short = true + end + + if( options.has_key?(:Objectify) && options[:Objectify] == true ) + objectify = true + end + + end + + # get number of subnets possible with the requested subnet_bits + num_avail = 2**(subnet_bits - my_mask) + + # get the number of bits in the next supernet and + # make sure num_subnets is a power of 2 + bits_needed = 1 + num_subnets = num_avail if (!num_subnets) + until (2**bits_needed >= num_subnets) + bits_needed += 1 + end + num_subnets = 2**bits_needed + next_supernet_bits = subnet_bits - bits_needed + + + # make sure subnet isnt bigger than available bits + if (subnet_bits > @address_len) + raise BoundaryError, "Requested subnet (#{subnet_bits}) does not fit " + + "within the bounds of IPv#{@version}." + end + + # make sure subnet is larger than mymask + if (subnet_bits < my_mask) + raise BoundaryError, "Requested subnet (#{subnet_bits}) is too large for " + + "current CIDR space." + end + + # make sure MinCount is smaller than available subnets + if (num_subnets > num_avail) + raise "Requested subnet count (#{num_subnets}) exceeds subnets " + + "available for allocation (#{num_avail})." + end + + # list all 'subnet_bits' sized subnets of this cidr block + # with a limit of num_subnets + bitstep = 2**(@address_len - subnet_bits) + subnets = self.enumerate(:Bitstep => bitstep, :Limit => num_subnets, :Objectify => true) + + # save our subnets + new_subnets = [] + subnets.each do |subnet| + if (!objectify) + if (short && @version == 6) + new_subnets.push("#{subnet.network(:Short => true)}/#{subnet_bits}") + else + new_subnets.push("#{subnet.network}/#{subnet_bits}") + end + else + new_subnets.push( NetAddr.cidr_build(@version, subnet.to_i(:network), NetAddr.bits_to_mask(subnet_bits,version) ) ) + end + end + + # now go through the rest of the cidr space and make the rest + # of the subnets. we want these to be as tightly merged as possible + next_supernet_bitstep = (bitstep * num_subnets) + next_supernet_ip = my_network + next_supernet_bitstep + until (next_supernet_bits == my_mask) + if (!objectify) + next_network = NetAddr.ip_int_to_str(next_supernet_ip, @version) + next_network = NetAddr.shorten(next_network) if (short && @version == 6) + new_subnets.push("#{next_network}/#{next_supernet_bits}") + else + new_subnets.push(NetAddr.cidr_build(@version, next_supernet_ip, NetAddr.bits_to_mask(next_supernet_bits,version) ) ) + end + + next_supernet_bits -= 1 + next_supernet_ip = next_supernet_ip + next_supernet_bitstep + next_supernet_bitstep = next_supernet_bitstep << 1 + end + + return(new_subnets) + end + +#===Synopsis +#Provide the next subnet following this CIDR object. The next subnet will +#be of the same size as the current CIDR object. +# +# Example: +# cidr = NetAddr::CIDR.create('192.168.1.0/24') +# cidr.succ => 192.168.2.0/24 +# +#===Arguments: +#* none +# +#===Returns: +#* NetAddr::CIDR object. +# + def succ() + bitstep = 2**(@address_len - self.bits) + next_sub = @network + bitstep + + if (next_sub > @all_f) + raise BoundaryError, "Returned subnet is out of bounds for IPv#{@version}." + end + + next_sub = NetAddr.cidr_build(@version,next_sub,self.to_i(:netmask)) + + return(next_sub) + end + +#===Synopsis +#Convert the requested attribute of the CIDR to an Integer. +# Example: +# cidr = NetAddr::CIDR.create('192.168.1.1/24') +# cidr.to_i => 3232235776 +# cidr.to_i(:hostmask) => 255 +# cidr.to_i(:ip) => 3232235777 +# cidr.to_i(:netmask) => 4294967040 +# cidr.to_i(:wildcard_mask) => 4294967040 +# +#===Arguments: +#* attribute -- attribute of the CIDR to convert to an Integer (:hostmask, :ip, :netmask, :network, or :wildcard_mask). +# +#===Returns: +#* Integer +# + def to_i(attribute=:network) + if(attribute == :network) + return(@network) + elsif(attribute == :hostmask) + return(@hostmask) + elsif(attribute == :ip) + return(@ip) + elsif(attribute == :netmask) + return(@netmask) + elsif(attribute == :wildcard_mask) + return(@wildcard_mask) + else + raise ArgumentError, "Attribute is unrecognized. Must be :hostmask, :ip, :netmask, :network, or :wildcard_mask." + end + end + +#===Synopsis +#Returns network/netmask in CIDR format. +# +# Example: +# cidr4 = NetAddr::CIDR.create('192.168.1.1/24') +# cidr6 = NetAddr::CIDR.create('fec0::/64') +# cidr4.desc(:IP => true) => "192.168.1.1/24" +# cidr4.to_s => "192.168.1.0/24" +# cidr6.to_s(:Short => true) => "fec0::/64" +# +#===Arguments: +#* options = Optional hash with the following keys: +# :IP -- if true, return the original ip/netmask passed during initialization +# :Short -- if true, return IPv6 addresses in short-hand notation +# +#===Returns: +#* String +# + def to_s(options=nil) + known_args = [:IP, :Short] + short = false + orig_ip = false + + if (options) + if (!options.kind_of? Hash) + raise ArgumentError, "Expected Hash, but #{options.class} provided." + end + NetAddr.validate_args(options.keys,known_args) + + if (options.has_key?(:Short) && options[:Short] == true) + short = true + end + + if (options.has_key?(:IP) && options[:IP] == true) + orig_ip = true + end + end + + if (!orig_ip) + ip = NetAddr.ip_int_to_str(@network, @version) + else + ip = NetAddr.ip_int_to_str(@ip, @version) + end + ip = NetAddr.shorten(ip) if (short && @version == 6) + mask = NetAddr.mask_to_bits(@netmask) + + return("#{ip}/#{mask}") + end + +#===Synopsis +#Return the wildcard mask. +# +# Example: +# cidr = NetAddr::CIDR.create('10.1.0.0/24', :WildcardMask => ['0.7.0.255', true]) +# cidr.wildcard_mask => "255.248.255.0" +# cidr.wildcard_mask(true) => "0.7.0.255" +# +#===Arguments: +#* bit_flipped = if set True then returned the bit-flipped version of the wildcard mask. +# +#===Returns: +#* String +# + def wildcard_mask(bit_flipped=false) + ret_val = nil + if (!bit_flipped) + ret_val = NetAddr.ip_int_to_str(@wildcard_mask, @version) + else + ret_val = NetAddr.ip_int_to_str(~@wildcard_mask, @version) + end + + return(ret_val) + end + +end # end class CIDR + + + + + +# IPv4 CIDR address - Inherits all methods from NetAddr::CIDR. +# Addresses of this class are composed of a 32-bit address space. +class CIDRv4 < CIDR + + public_class_method :new + +# Alias for last + alias :broadcast :last + +#===Synopsis +#Provide IPv4 Hostmask in extended format (y.y.y.y). +# +# Example: +# cidr = NetAddr::CIDR.create('10.1.0.0/24') +# cidr.hostmask_ext => "0.0.0.255" +# +#===Arguments: +#* none +# +#===Returns: +#* String +# + def hostmask_ext() + return(NetAddr.ip_int_to_str(@hostmask, @version)) + end + +#===Synopsis +#Provide IPv4 netmask in extended format (y.y.y.y). +# +# Example: +# cidr = NetAddr::CIDR.create('10.1.0.0/24') +# cidr.netmask_ext => "255.255.255.0" +# +#===Arguments: +#* none +# +#===Returns: +#* String +# + def netmask_ext() + return(NetAddr.ip_int_to_str(@netmask, 4)) + end + +end # end class CIDRv4 + + + + + + + + +# IPv6 CIDR address - Inherits all methods from NetAddr::CIDR. +# Addresses of this class are composed of a 128-bit address space. +class CIDRv6 < CIDR + public_class_method :new + +#===Synopsis +#Generate an IPv6 Unique Local CIDR address based on the algorithm described +#in RFC 4193. +# +#From the RFC: +# +# 1) Obtain the current time of day in 64-bit NTP format [NTP]. +# +# 2) Obtain an EUI-64 identifier from the system running this +# algorithm. If an EUI-64 does not exist, one can be created from +# a 48-bit MAC address as specified in [ADDARCH]. If an EUI-64 +# cannot be obtained or created, a suitably unique identifier, +# local to the node, should be used (e.g., system serial number). +# +# 3) Concatenate the time of day with the system-specific identifier +# in order to create a key. +# +# 4) Compute an SHA-1 digest on the key as specified in [FIPS, SHA1]; +# the resulting value is 160 bits. +# +# 5) Use the least significant 40 bits as the Global ID. +# +# 6) Concatenate FC00::/7, the L bit set to 1, and the 40-bit Global +# ID to create a Local IPv6 address prefix. +# +# Example: +# eui = NetAddr::EUI.create('aabb.ccdd.eeff') +# NetAddr::CIDRv6.unique_local(eui) => fdb4:3014:e277:0000:0000:0000:0000:0000/48 +# +#===Arguments: +#* NetAddr::EUI object +# +#===Returns: +#* CIDRv6 object +# + def CIDRv6.unique_local(eui) + + if (eui.kind_of?(NetAddr::EUI48) ) + eui = eui.to_eui64.to_s + elsif (eui.kind_of?(NetAddr::EUI64) ) + eui = eui.to_s + else + raise ArgumentError, "Expected NetAddr::EUI object but #{eui.class} received." + end + + ntp_time = '' + + # get current time (32-bits), convert to 4-byte string, and append to ntp_time + time = Time.now.to_i + 4.times do + ntp_time.insert(0, (time & 0xff).chr ) + time = time >> 8 + end + + # create 32-bit fractional, convert to 4-byte string, and append to ntp_time + fract = rand(2**32-1) + 4.times do + ntp_time.insert(0, (fract & 0xff).chr ) + fract = fract >> 8 + end + + # create sha1 hash + pre_hash = ntp_time << eui + gid = Digest::SHA1.hexdigest(pre_hash).slice!(30..39) + addr = 'fd' << gid << '00000000000000000000' + + return( NetAddr::CIDRv6.new(addr.to_i(16), 0xffffffffffff00000000000000000000 ) ) + end + +end # end class CIDRv6 + +end # module NetAddr +__END__ diff --git a/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/cidr_shortcuts.rb b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/cidr_shortcuts.rb new file mode 100644 index 00000000000..fcf61e68b81 --- /dev/null +++ b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/cidr_shortcuts.rb @@ -0,0 +1,401 @@ +module NetAddr +private + +# CIDR METHODS + +# create either a CIDRv4 or CIDRv6 object +# +def cidr_build(version, ip, netmask=nil, tag={}, wildcard_mask=nil, wildcard_mask_bit_flipped=false) + return( NetAddr::CIDRv4.new(ip, netmask, tag, wildcard_mask, wildcard_mask_bit_flipped) ) if (version == 4) + return( NetAddr::CIDRv6.new(ip, netmask, tag, wildcard_mask, wildcard_mask_bit_flipped) ) +end +module_function :cidr_build + + +# compare 2 CIDR objects +# +#return: +#* 1 if the cidr1 contains cidr2 +#* 0 if the cidr1 and cidr2 are equal +#* -1 if cidr1 is a subnet of cidr2 +#* nil if the two are unrelated +# +def cidr_compare(cidr1,cidr2) + comparasin = nil + if ( cidr1.to_i(:network) == cidr2.to_i(:network) ) + # same network, check netmask + if (cidr1.to_i(:netmask) == cidr2.to_i(:netmask) ) + comparasin = 0 + elsif(cidr1.to_i(:netmask) < cidr2.to_i(:netmask)) + comparasin = 1 + elsif(cidr1.to_i(:netmask) > cidr2.to_i(:netmask)) + comparasin = -1 + end + + elsif( (cidr2.to_i(:network) | cidr1.to_i(:hostmask)) == (cidr1.to_i(:network) | cidr1.to_i(:hostmask)) ) + # cidr1 contains cidr2 + comparasin = 1 + + elsif( (cidr2.to_i(:network) | cidr2.to_i(:hostmask)) == (cidr1.to_i(:network) | cidr2.to_i(:hostmask)) ) + # cidr2 contains cidr1 + comparasin = -1 + end + + return(comparasin) +end +module_function :cidr_compare + +# given a pair of CIDRs, determine if first is greater than or less than the second +# +# return 1 if cidr1 > cidr2 +# return 0 if cidr1 == cidr2 +# return -1 if cidr1 < cidr2 +# +def cidr_gt_lt(cidr1,cidr2) + gt_lt = 1 + if(cidr1.to_i(:network) < cidr2.to_i(:network)) + gt_lt = -1 + elsif (cidr1.to_i(:network) == cidr2.to_i(:network)) + if (cidr1.to_i(:netmask) < cidr2.to_i(:netmask)) + gt_lt = -1 + elsif (cidr1.to_i(:netmask) == cidr2.to_i(:netmask)) + gt_lt = 0 + end + end + + return(gt_lt) +end +module_function :cidr_gt_lt + +#Given a list of subnets of supernet, return a new list with any +#holes (missing subnets) filled in. +# +def cidr_fill_in(supernet,list) + # sort our cidr's and see what is missing + complete_list = [] + expected = supernet.to_i(:network) + all_f = supernet.all_f + + NetAddr.cidr_sort(list).each do |cidr| + network = cidr.to_i(:network) + bitstep = (all_f + 1) - cidr.to_i(:netmask) + + if (network > expected) # missing space at beginning of supernet, so fill in the hole + num_ips_missing = network - expected + sub_list = cidr_make_subnets_from_base_and_ip_count(supernet,expected,num_ips_missing) + complete_list.concat(sub_list) + elsif (network < expected) + next + end + + complete_list.push(cidr) + expected = network + bitstep + end + + # if expected is not the next subnet, then we're missing subnets + # at the end of the cidr + next_sub = supernet.next_subnet(:Objectify => true).to_i(:network) + if (expected != next_sub) + num_ips_missing = next_sub - expected + sub_list = cidr_make_subnets_from_base_and_ip_count(supernet,expected,num_ips_missing) + complete_list.concat(sub_list) + end + + return(complete_list) +end +module_function :cidr_fill_in + +# evaluate cidr against list of cidrs. +# +# return entry from list if entry is supernet of cidr (first matching entry) +# return index # of entry if entry is a duplicate of cidr +# return nil if no match found +# +def cidr_find_in_list(cidr,list) + return(nil) if (list.length == 0) + + match = nil + low = 0 + high = list.length - 1 + index = low + ( (high-low)/2 ) + while ( low <= high) + cmp = cidr_gt_lt(cidr,list[index]) + if ( cmp == -1 ) + high = index - 1 + + elsif ( cmp == 1 ) + if (cidr_compare(cidr,list[index]) == -1) + match = list[index] + break + end + low = index + 1 + + else + match = index + break + end + index = low + ( (high-low)/2 ) + end + return(match) +end +module_function :cidr_find_in_list + +# Make CIDR addresses from a base addr and an number of ip's to encapsulate. +# +#===Arguments: +# * cidr +# * base ip as integer +# * number of ip's required +# +#===Returns: +# * array of NetAddr::CIDR objects +# + def cidr_make_subnets_from_base_and_ip_count(cidr,base_addr,ip_count) + list = [] + until (ip_count == 0) + mask = cidr.all_f + multiplier = 0 + bitstep = 0 + last_addr = base_addr + done = false + until (done == true) + if (bitstep < ip_count && (base_addr & mask == last_addr & mask) ) + multiplier += 1 + elsif (bitstep > ip_count || (base_addr & mask != last_addr & mask) ) + multiplier -= 1 + done = true + else + done = true + end + bitstep = 2**multiplier + mask = cidr.all_f << multiplier & cidr.all_f + last_addr = base_addr + bitstep - 1 + end + + list.push(NetAddr.cidr_build(cidr.version,base_addr,mask)) + ip_count -= bitstep + base_addr += bitstep + end + + return(list) + end +module_function :cidr_make_subnets_from_base_and_ip_count + +# given a list of NetAddr::CIDRs, return them as a sorted list +# +def cidr_sort(list, desc=false) + # uses simple quicksort algorithm + sorted_list = [] + if (list.length < 1) + sorted_list = list + else + less_list = [] + greater_list = [] + equal_list = [] + pivot = list[rand(list.length)] + if (desc) + list.each do |x| + if ( pivot.to_i(:network) < x.to_i(:network) ) + less_list.push(x) + elsif ( pivot.to_i(:network) > x.to_i(:network) ) + greater_list.push(x) + else + if ( pivot.to_i(:netmask) < x.to_i(:netmask) ) + greater_list.push(x) + elsif ( pivot.to_i(:netmask) > x.to_i(:netmask) ) + less_list.push(x) + else + equal_list.push(x) + end + end + end + else + list.each do |x| + gt_lt = cidr_gt_lt(pivot,x) + if (gt_lt == 1) + less_list.push(x) + elsif (gt_lt == -1) + greater_list.push(x) + else + equal_list.push(x) + end + end + end + + sorted_list.concat( cidr_sort(less_list, desc) ) + sorted_list.concat(equal_list) + sorted_list.concat( cidr_sort(greater_list, desc) ) + end + + return(sorted_list) +end +module_function :cidr_sort + +# given a list of NetAddr::CIDRs (of the same version) summarize them +# +# return a hash, with the key = summary address and val = array of original cidrs +# +def cidr_summarize(subnet_list) + all_f = subnet_list[0].all_f + version = subnet_list[0].version + subnet_list = cidr_sort(subnet_list) + + # continue summarization attempts until sorted_list stops getting shorter + sorted_list = subnet_list.dup + sorted_list_len = sorted_list.length + while (1) + summarized_list = [] + until (sorted_list.length == 0) + cidr = sorted_list.shift + network, netmask = cidr.to_i(:network), cidr.to_i(:netmask) + supermask = (netmask << 1) & all_f + supernet = supermask & network + + if (network == supernet && sorted_list.length > 0) + # network is lower half of supernet, so see if we have the upper half + bitstep = (all_f + 1) - netmask + expected = network + bitstep + next_cidr = sorted_list.shift + next_network, next_netmask = next_cidr.to_i(:network), next_cidr.to_i(:netmask) + + if ( (next_network == expected) && (next_netmask == netmask) ) + # we do indeed have the upper half. store new supernet. + summarized_list.push( cidr_build(version,supernet,supermask) ) + else + # we do not have the upper half. put next_cidr back into sorted_list + # and store only the original network + sorted_list.unshift(next_cidr) + summarized_list.push(cidr) + end + else + # network is upper half of supernet, so save original network only + summarized_list.push(cidr) + end + + end + + sorted_list = summarized_list.dup + break if (sorted_list.length == sorted_list_len) + sorted_list_len = sorted_list.length + end + + # clean up summarized_list + unique_list = {} + summarized_list.reverse.each do |supernet| + next if ( unique_list.has_key?(supernet.desc) ) + # remove duplicates + unique_list[supernet.desc] = supernet + + # remove any summary blocks that are children of other summary blocks + index = 0 + until (index >= summarized_list.length) + subnet = summarized_list[index] + if (subnet && cidr_compare(supernet,subnet) == 1 ) + unique_list.delete(subnet.desc) + end + index += 1 + end + end + summarized_list = unique_list.values + + # map original blocks to their summaries + summarized_list.each do |supernet| + supernet.tag[:Subnets] = [] + index = 0 + until (index >= subnet_list.length) + subnet = subnet_list[index] + if (subnet && cidr_compare(supernet,subnet) == 1 ) + subnet_list[index] = nil + supernet.tag[:Subnets].push(subnet) + end + index += 1 + end + end + + return( NetAddr.cidr_sort(summarized_list) ) +end +module_function :cidr_summarize + +# given a list of NetAddr::CIDRs (of the same version), return only the 'top level' blocks (i.e. blocks not +# contained by other blocks + +def cidr_supernets(subnet_list) + summary_list = [] + subnet_list = netmask_sort(subnet_list) + subnet_list.each do |child| + is_parent = true + summary_list.each do |parent| + if (NetAddr.cidr_compare(parent,child) == 1) + is_parent = false + parent.tag[:Subnets].push(child) + end + end + + if (is_parent) + child.tag[:Subnets] = [] + summary_list.push(child) + end + end + + return(summary_list) +end +module_function :cidr_supernets + +# given a list of NetAddr::CIDRs, return them as a sorted (by netmask) list +# +def netmask_sort(list, desc=false) + # uses simple quicksort algorithm + sorted_list = [] + if (list.length < 1) + sorted_list = list + else + less_list = [] + greater_list = [] + equal_list = [] + pivot = list[rand(list.length)] + if (desc) + list.each do |x| + if ( pivot.to_i(:netmask) < x.to_i(:netmask) ) + less_list.push(x) + elsif ( pivot.to_i(:netmask) > x.to_i(:netmask) ) + greater_list.push(x) + else + if ( pivot.to_i(:network) < x.to_i(:network) ) + greater_list.push(x) + elsif ( pivot.to_i(:network) > x.to_i(:network) ) + less_list.push(x) + else + equal_list.push(x) + end + end + end + else + list.each do |x| + if ( pivot.to_i(:netmask) < x.to_i(:netmask) ) + greater_list.push(x) + elsif ( pivot.to_i(:netmask) > x.to_i(:netmask) ) + less_list.push(x) + else + if ( pivot.to_i(:network) < x.to_i(:network) ) + greater_list.push(x) + elsif ( pivot.to_i(:network) > x.to_i(:network) ) + less_list.push(x) + else + equal_list.push(x) + end + end + end + end + + sorted_list.concat( netmask_sort(less_list, desc) ) + sorted_list.concat(equal_list) + sorted_list.concat( netmask_sort(greater_list, desc) ) + end + + return(sorted_list) +end +module_function :netmask_sort + +end # module NetAddr + +__END__ \ No newline at end of file diff --git a/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/eui.rb b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/eui.rb new file mode 100644 index 00000000000..c34d4aeaf3b --- /dev/null +++ b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/eui.rb @@ -0,0 +1,402 @@ +module NetAddr + +#=EUI - Extended Unique Identifier +# +#A class & series of methods for creating and manipulating Extended Unique Identifier +#(EUI) addresses. Two types of address formats are supported EUI-48 and EUI-64. The +#most common use for this class will be to manipulate MAC addresses (which are essentially +#a type of EUI-48 address). +# +#EUI addresses are separated into two parts, the +#Organizationally Unique Identifier (OUI) and the Extended Identifier (EI). The OUI +#is assigned by the IEEE and is used to identify a particular hardware manufacturer. +#The EI is assigned by the hardware manufacturer as a per device unique address. +# +#Probably the most useful feature of this class, and thus the reason it was created, +#is to help automate certain address assignments within IP. For example, IPv6 +#Link Local addresses use MAC addresses for IP auto-assignment and multicast MAC addresses +#are determined based on the multicast IP address. +# +class EUI + +private_class_method :new + +#===Synopsis +# This method performs absolutely no error checking, and is meant to be used only by +# other internal methods for the sake of the speedier creation of EUI objects. +# Please consider using #create unless you know what you are doing with 100% certainty. +# +# Example: +# NetAddr::EUI48.new('aabbccddeeff') +# +#===Arguments: +#* EUI as a String or Integer. Strings should contain no formatting characters. +# + def initialize(eui) + + if (eui.kind_of?(Integer)) + @eui_i = eui + @eui = eui.to_s(16) + if ( self.kind_of?(NetAddr::EUI48) ) + @eui = '0' * (12 - @eui.length) << @eui if (@eui.length < 12) + else + @eui = '0' * (16 - @eui.length) << @eui if (@eui.length < 16) + end + + elsif(eui.kind_of?(String)) + @eui = eui + @eui_i = eui.to_i(16) + else + raise ArgumentError, "Expected String or Integer, but #{eui.class} provided." + end + + # set ei & oui + if ( self.kind_of?(NetAddr::EUI48) ) + @ei = @eui.slice(6..11) + else + @ei = @eui.slice(6..15) + end + + @oui = @eui.slice(0..5) + + end + +#===Synopsis +#Create a new EUI48 or EUI64 object. +# +# Example: +# addr = NetAddr::EUI.create('aa-bb-cc-dd-ee-ff') +# addr = NetAddr::EUI.create('aa:bb:cc:dd:ee:ff') +# addr = NetAddr::EUI.create('aabb.ccdd.eeff') +# addr = NetAddr::EUI.create('aa-bb-cc-dd-ee-ff-00-01') +# +#===Arguments +#* eui = EUI as a String +# +#===Returns +#* EUI48 or EUI64 object +# + def EUI.create(eui) + if (!eui.kind_of? String) + raise ArgumentError, "Expected String, but #{eui.class} provided." + end + + # create local copy & validate + eui = eui.dup + NetAddr.validate_eui(eui) + + # remove formatting characters + eui.gsub!(/[\.\:\-]/, '') + + if (eui.length == 12) + eui = NetAddr::EUI48.new(eui) + else + eui = NetAddr::EUI64.new(eui) + end + + return(eui) + end + +#===Synopsis +# Returns EUI address. The default address format is xxxx.xxxx.xxxx +# +# Example: +# addr = NetAddr::EUI.create('aabb.ccdd.eeff') +# addr.address(:Delimiter => '-') => "aa-bb-cc-dd-ee-ff" +# addr.address(:Delimiter => ':') => "aa:bb:cc:dd:ee:ff" +# +#===Arguments: +#* options = Hash with the following fields: +# :Delimiter -- delimitation character. valid values are (- : .) +# +#===Returns: +#* String +# + def address(options=nil) + known_args = [:Delimiter] + delimiter = '-' + + if (options) + if (!options.kind_of? Hash) + raise ArgumentError, "Expected Hash, but #{options.class} provided." + end + NetAddr.validate_args(options.keys,known_args) + + if (options.has_key?(:Delimiter)) + delimiter = options[:Delimiter] + delimiter = '-' if (delimiter != ':' && delimiter != '.') + end + end + + if (delimiter == '-' || delimiter == ':') + addr = octets.join(delimiter) + elsif (delimiter == '.') + addr = octets.each_slice(2).to_a.map(&:join).join('.') + end + + return(addr) + end + +#===Synopsis +#Returns Extended Identifier portion of an EUI address (the vendor assigned ID). +#The default address format is xx-xx-xx +# +# Example: +# addr = NetAddr::EUI.create('aabb.ccdd.eeff') +# addr.ei(:Delimiter => '-') => "dd-ee-ff" +# +#===Arguments: +#* options = Hash with the following fields: +# :Delimiter -- delimitation character. valid values are (-, and :) +# +#===Returns: +#* String +# + def ei(options=nil) + known_args = [:Delimiter] + delimiter = '-' + + if (options) + if (!options.kind_of? Hash) + raise ArgumentError, "Expected Hash, but #{options.class} provided." + end + NetAddr.validate_args(options.keys,known_args) + + if (options.has_key?(:Delimiter)) + if (options[:Delimiter] == ':') + delimiter = options[:Delimiter] + end + end + end + + if ( self.kind_of?(NetAddr::EUI48) ) + ei = octets[3..5].join(delimiter) + else + ei = octets[3..7].join(delimiter) + end + + return(ei) + end + +#===Synopsis +# Provide an IPv6 Link Local address based on the current EUI address. +# +# Example: +# addr = NetAddr::EUI.create('aabb.ccdd.eeff') +# addr.link_local() => "fe80:0000:0000:0000:aabb:ccff:fedd:eeff" +# +#===Arguments: +#* options = Hash with the following fields: +# :Short -- if true, return IPv6 addresses in short-hand notation +# :Objectify -- if true, return CIDR objects +# +#===Returns: +#* CIDR address String or an NetAddr::CIDR object +# + def link_local(options=nil) + return( self.to_ipv6('fe80::/64', options) ) + end + +#===Synopsis +#Returns Organizationally Unique Identifier portion of an EUI address (the vendor ID). +#The default address format is xx-xx-xx. +# +# Example: +# addr = NetAddr::EUI.create('aabb.ccdd.eeff') +# addr.oui(:Delimiter => '-') => "aa-bb-cc" +# +#===Arguments: +#* options = Hash with the following fields: +# :Delimiter -- delimitation character. valid values are (-, and :) +# +#===Returns: +#* String +# + def oui(options=nil) + known_args = [:Delimiter] + delimiter = '-' + + if (options) + if (!options.kind_of? Hash) + raise ArgumentError, "Expected Hash, but #{options.class} provided." + end + NetAddr.validate_args(options.keys,known_args) + + if (options.has_key?(:Delimiter)) + if (options[:Delimiter] == ':') + delimiter = options[:Delimiter] + end + end + end + oui = octets[0..2].join(delimiter) + + return(oui) + end + +#===Synopsis +#Returns the EUI as an Integer. +# +# Example: +# addr = NetAddr::EUI.create('aabb.ccdd.eeff') +# addr.to_i => 187723572702975 +# +#===Arguments: +#* none +# +#===Returns: +#* Integer +# + def to_i() + return(@eui_i) + end + +#===Synopsis +# Given a valid IPv6 subnet, return an IPv6 address based on the current EUI. +# +# Example: +# addr = NetAddr::EUI.create('aabb.ccdd.eeff') +# addr.to_ipv6('3ffe::/64') => "3ffe:0000:0000:0000:a8bb:ccff:fedd:eeff" +# +#===Arguments: +#* options = Hash with the following fields: +# :Short -- if true, return IPv6 addresses in short-hand notation +# :Objectify -- if true, return CIDR objects +# +#===Returns: +#* IPv6 address String or an NetAddr::CIDRv6 object +# + def to_ipv6(cidr, options=nil) + known_args = [:Short, :Objectify] + objectify = false + short = false + + if ( !cidr.kind_of?(NetAddr::CIDR) ) + begin + cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "CIDR raised the following errors: #{error}" + end + elsif (cidr.kind_of?(NetAddr::CIDRv4) ) + raise ArgumentError, "Expected CIDRv6, but #{cidr.class} provided." + end + + if (cidr.bits > 64) + raise ValidationError, "Prefix length of provided CIDR must be /64 or less but was #{cidr.netmask}." + end + + if (options) + if (!options.kind_of? Hash) + raise ArgumentError, "Expected Hash, but #{options.class} provided." + end + NetAddr.validate_args(options.keys,known_args) + + if (options.has_key?(:Objectify) && options[:Objectify] == true) + objectify = true + end + + if (options.has_key?(:Short) && options[:Short] == true) + short = true + end + end + + # get integer equiv of addr. conver eui48 to eui64 if needed + if ( self.kind_of?(NetAddr::EUI48) ) + eui_i = self.to_eui64.to_i + else + eui_i = self.to_i + end + + # toggle u/l bit + eui_i = eui_i ^ 0x0200000000000000 + + # create ipv6 address + ipv6 = cidr.to_i | eui_i + + if (!objectify) + ipv6 = NetAddr.i_to_ip(ipv6, :Version => 6) + ipv6 = NetAddr.shorten(ipv6) if (short) + else + ipv6 = NetAddr::CIDRv6.new(ipv6) + end + + return(ipv6) + end + +#===Synopsis +#Returns the EUI as an unformatted String. +# +# Example: +# addr = NetAddr::EUI.create('aabb.ccdd.eeff') +# addr.to_s => "aabbccddeeff" +# +#===Arguments: +#* none +# +#===Returns: +#* String +# + def to_s() + return(@eui) + end + +private + +#Returns array with each element representing a single octet of the eui. +# + def octets() + return(@octets) if (@octets) + + @octets = [] + str = '' + @eui.each_byte do |chr| + str = str << chr + if (str.length == 2) + @octets.push(str) + str = '' + end + end + + return(@octets) + end + +end + + + +# EUI-48 Address - Inherits all methods from NetAddr::EUI. +# Addresses of this class have a 24-bit OUI and a 24-bit EI. +class EUI48 < EUI + + public_class_method :new + +#===Synopsis +#Return an EUI64 address based on the current EUI48 address. +# +# Example: +# addr = NetAddr::EUI.create('aabb.ccdd.eeff') +# addr.to_eui64 => NetAddr::EUI64 +# +#===Arguments: +#* none +# +#===Returns: +#* NetAddr::EUI64 object +# + def to_eui64() + eui = @oui + 'fffe' + @ei + return( NetAddr::EUI64.new(eui.to_i(16)) ) + end + +end + + + +# EUI-64 Address - Inherits all methods from NetAddr::EUI. +# Addresses of this class have a 24-bit OUI and a 40-bit EI. +class EUI64 < EUI + public_class_method :new +end + + +end # module NetAddr +__END__ diff --git a/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/ip_math.rb b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/ip_math.rb new file mode 100644 index 00000000000..4cb030f06e8 --- /dev/null +++ b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/ip_math.rb @@ -0,0 +1,227 @@ +module NetAddr +private + + +# IP MATH METHODS + +# given an integer and number of bits to consider, return its binary mirror +# +def binary_mirror(num, bit_count) + mirror = 0 + bit_count.times do # make mirror image of num by capturning lsb and left-shifting it onto mirror + mirror = mirror << 1 + lsb = num & 1 + num = num >> 1 + mirror = mirror | lsb + end + return(mirror) +end +module_function :binary_mirror + +# convert a netmask (in bits) to an integer mask +# +def bits_to_mask(netmask,version) + return(0) if (netmask == 0) + all_f = 2**32-1 + all_f = 2**128-1 if (version == 6) + return( all_f ^ (all_f >> netmask) ) +end +module_function :bits_to_mask + +# determine the ip version from ip address string. +# +# return 4, 6, or nil +# +def detect_ip_version(ip) + version = nil + if ( ip =~ /\./ && ip !~ /:/ ) + version = 4 + elsif (ip =~ /:/) + version = 6 + else + raise ValidationError, "Could not auto-detect IP version for '#{ip}'." + end + return(version) +end +module_function :detect_ip_version + +# given an ip count, determine the most appropriate mask (in bits) +# +def ip_count_to_size(ipcount,version,extended=false) + address_len = 32 + address_len = 128 if (version == 6 ) + + if (ipcount > 2**address_len) + raise BoundaryError, "Required IP count exceeds number of IP addresses available " + + "for IPv#{version}." + end + + bits_needed = 0 + until (2**bits_needed >= ipcount) + bits_needed += 1 + end + subnet_bits = address_len - bits_needed + + return( ip_int_to_str(bits_to_mask(subnet_bits, 4), 4) ) if (extended && version == 4) + return(subnet_bits) +end +module_function :ip_count_to_size + +# unpack an int into an ip address string +# +def ip_int_to_str(ip_int, version, ipv4_mapped=nil) + ip = nil + version = 4 if (!version && ip_int < 2**32) + if (version == 4) + octets = [] + 4.times do + octet = ip_int & 0xFF + octets.unshift(octet.to_s) + ip_int = ip_int >> 8 + end + ip = octets.join('.') + else + fields = [] + if (!ipv4_mapped) + loop_count = 8 + else + loop_count = 6 + ipv4_int = ip_int & 0xffffffff + ipv4_addr = ip_int_to_str(ipv4_int, 4) + fields.unshift(ipv4_addr) + ip_int = ip_int >> 32 + end + + loop_count.times do + octet = ip_int & 0xFFFF + octet = octet.to_s(16) + ip_int = ip_int >> 16 + + # if octet < 4 characters, then pad with 0's + (4 - octet.length).times do + octet = '0' << octet + end + fields.unshift(octet) + end + ip = fields.join(':') + end + return(ip) +end +module_function :ip_int_to_str + +# convert an ip string into an int +# +def ip_str_to_int(ip,version) + ip_int = 0 + if ( version == 4) + octets = ip.split('.') + (0..3).each do |x| + octet = octets.pop.to_i + octet = octet << 8*x + ip_int = ip_int | octet + end + + else + # if ipv4-mapped ipv6 addr + if (ip =~ /\./) + dotted_dec = true + end + + # split up by ':' + fields = [] + if (ip =~ /::/) + shrthnd = ip.split( /::/ ) + if (shrthnd.length == 0) + return(0) + else + first_half = shrthnd[0].split( /:/ ) if (shrthnd[0]) + sec_half = shrthnd[1].split( /:/ ) if (shrthnd[1]) + first_half = [] if (!first_half) + sec_half = [] if (!sec_half) + end + missing_fields = 8 - first_half.length - sec_half.length + missing_fields -= 1 if dotted_dec + fields = fields.concat(first_half) + missing_fields.times {fields.push('0')} + fields = fields.concat(sec_half) + + else + fields = ip.split(':') + end + + if (dotted_dec) + ipv4_addr = fields.pop + ipv4_int = NetAddr.ip_to_i(ipv4_addr, :Version => 4) + octets = [] + 2.times do + octet = ipv4_int & 0xFFFF + octets.unshift(octet.to_s(16)) + ipv4_int = ipv4_int >> 16 + end + fields.concat(octets) + end + + # pack + (0..7).each do |x| + field = fields.pop.to_i(16) + field = field << 16*x + ip_int = ip_int | field + end + + end + return(ip_int) +end +module_function :ip_str_to_int + +# convert integer into a cidr formatted netmask (bits) +# +def mask_to_bits(netmask_int) + return(netmask_int) if (netmask_int == 0) + + mask = nil + if (netmask_int < 2**32) + mask = 32 + validate_netmask_int(netmask_int, 4, true) + else + mask = 128 + validate_netmask_int(netmask_int, 6, true) + end + + mask.times do + if ( (netmask_int & 1) == 1) + break + end + netmask_int = netmask_int >> 1 + mask = mask - 1 + end + return(mask) +end +module_function :mask_to_bits + +# convert string into integer mask +# +def netmask_str_to_int(netmask,version) + netmask_int = nil + all_f = 2**32-1 + all_f = 2**128-1 if (version == 6) + if(netmask =~ /\./) + netmask_int = NetAddr.ip_to_i(netmask) + else + # remove '/' if present + if (netmask =~ /^\// ) + netmask[0] = " " + netmask.lstrip! + end + netmask = netmask.to_i + netmask_int = all_f ^ (all_f >> netmask) + end + return(netmask_int) +end +module_function :netmask_str_to_int + + + +end # module NetAddr + +__END__ + diff --git a/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/methods.rb b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/methods.rb new file mode 100644 index 00000000000..b4958cad8e8 --- /dev/null +++ b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/methods.rb @@ -0,0 +1,1013 @@ +module NetAddr + +#===Synopsis +#Convert an Integer representing a binary netmask into an Integer representing +#the number of bits in that netmask. +# +# Example: +# NetAddr.i_to_bits(0xfffffffe) => 31 +# NetAddr.i_to_bits(0xffffffffffffffff0000000000000000) => 64 +# +#===Arguments: +#* netmask_int = Integer representing a binary netmask +# +#===Returns: +#* Integer +# +def i_to_bits(netmask_int) + + # validate netmask_int + raise ArgumentError, "Integer expected for argument 'netmask_int', " + + "but #{netmask_int.class} provided." if (!netmask_int.kind_of?(Integer)) + + + return( mask_to_bits(netmask_int) ) +end +module_function :i_to_bits + +#===Synopsis +#Convert an Integer into an IP address. This method will attempt to auto-detect the IP version +#if not provided, however, a slight speed increase is realized if version is provided. +# +# Example: +# NetAddr.i_to_ip(3232235906) => "192.168.1.130" +# NetAddr.i_to_ip(0xffff0000000000000000000000000001, :Version => 6) => "ffff:0000:0000:0000:0000:0000:0000:0001" +# +#===Arguments: +#* ip_int = IP address as an Integer +#* options = Hash with the following keys: +# :Version -- IP version - Integer (optional) +# :IPv4Mapped -- if true, unpack IPv6 as an IPv4 mapped address (optional) +# +#===Returns: +#* String +# +def i_to_ip(ip_int, options=nil) + known_args = [:Version, :IPv4Mapped] + ipv4_mapped = false + version = nil + + # validate options + if (options) + raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash)) + NetAddr.validate_args(options.keys,known_args) + + if (options.has_key?(:Version)) + version = options[:Version] + if (version != 4 && version != 6) + raise VersionError, ":Version should be 4 or 6, but was '#{version}'." + end + end + + if (options.has_key?(:IPv4Mapped) && options[:IPv4Mapped] == true) + ipv4_mapped = true + end + end + + # validate & unpack + raise ArgumentError, "Integer expected for argument 'ip_int', " + + "but #{ip_int.class} provided." if (!ip_int.kind_of?(Integer)) + version = validate_ip_int(ip_int, version) + ip = ip_int_to_str(ip_int, version, ipv4_mapped) + + return(ip) +end +module_function :i_to_ip + +#===Synopsis +#Convert IP addresses into an Integer. This method will attempt to auto-detect the IP version +#if not provided, however a slight speed increase is realized if version is provided. +# +# Example: +# NetAddr.ip_to_i('192.168.1.1') => 3232235777 +# NetAddr.ip_to_i('ffff::1', :Version => 6) => 340277174624079928635746076935438991361 +# NetAddr.ip_to_i('::192.168.1.1') => 3232235777 +# +#===Arguments: +#* ip = IP address as a String +#* options = Hash with the following keys: +# :Version -- IP version - Integer +# +#===Returns: +#* Integer +# +def ip_to_i(ip, options=nil) + known_args = [:Version] + to_validate = {} + version = nil + + # validate options + if (options) + raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash)) + validate_args(options.keys,known_args) + + if (options.has_key?(:Version)) + version = options[:Version] + to_validate[:Version] = version + if (version != 4 && version != 6) + raise VersionError, ":Version should be 4 or 6, but was '#{version}'." + end + end + end + + if ( ip.kind_of?(String) ) + version = detect_ip_version(ip) if (!version) + validate_ip_str(ip,version) + ip_int = ip_str_to_int(ip,version) + + else + raise ArgumentError, "String expected for argument 'ip' but #{ip.class} provided." + end + + return(ip_int) +end +module_function :ip_to_i + +#===Synopsis +#Given a list of CIDR addresses or NetAddr::CIDR objects, +#merge (summarize) them in the most efficient way possible. Summarization +#will only occur when the newly created supernets will not result in the +#'creation' of new IP space. For example the following blocks +#(192.168.0.0/24, 192.168.1.0/24, and 192.168.2.0/24) would be summarized into +#192.168.0.0/23 and 192.168.2.0/24 rather than into 192.168.0.0/22 +# +#I have designed this with enough flexibility so that you can pass in CIDR +#addresses that arent even related (ex. 192.168.1.0/26, 192.168.1.64/27, 192.168.1.96/27 +#10.1.0.0/26, 10.1.0.64/26) and they will be merged properly (ie 192.168.1.0/25, +#and 10.1.0.0/25 would be returned). +# +#If the :Objectify option is enabled, then any summary addresses returned will +#contain the original CIDRs used to create them within the tag value :Subnets +#(ie. cidr_x.tag[:Subnets] would be an Array of the CIDRs used to create cidr_x) +# +# Example: +# cidr1 = NetAddr::CIDR.create('192.168.1.0/27') +# cidr2 = NetAddr::CIDR.create('192.168.1.32/27') +# NetAddr.merge([cidr1,cidr2]) +# ip_net_range = NetAddr.range('192.168.35.0','192.168.39.255',:Inclusive => true, :Objectify => true) +# NetAddr.merge(ip_net_range, :Objectify => true) +# +#===Arguments: +#* list = Array of CIDR addresses as Strings, or an Array of NetAddr::CIDR objects +#* options = Hash with the following keys: +# :Objectify -- if true, return NetAddr::CIDR objects +# :Short -- if true, return IPv6 addresses in short-hand notation +# +#===Returns: +#* Array of CIDR addresses or NetAddr::CIDR objects +# +def merge(list,options=nil) + known_args = [:Objectify, :Short] + short = false + objectify = false + verbose = false + + # validate list + raise ArgumentError, "Array expected for argument 'list' but #{list.class} provided." if (!list.kind_of?(Array) ) + + # validate options + if (options) + raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash) ) + NetAddr.validate_args(options.keys,known_args) + + if (options.has_key?(:Objectify) && options[:Objectify] == true) + objectify = true + end + + if (options.has_key?(:Short) && options[:Short] == true) + short = true + end + end + + # make sure all are valid types of the same IP version + v4_list = [] + v6_list = [] + list.each do |obj| + if (!obj.kind_of?(NetAddr::CIDR)) + begin + obj = NetAddr::CIDR.create(obj) + rescue Exception => error + raise ArgumentError, "One of the provided CIDR addresses raised the following " + + "errors: #{error}" + end + end + + if (obj.version == 4) + v4_list.push(obj) + else + v6_list.push(obj) + end + end + + # summarize + v4_summary = [] + v6_summary = [] + if (v4_list.length != 0) + v4_summary = NetAddr.cidr_summarize(v4_list) + end + + if (v6_list.length != 0) + v6_summary = NetAddr.cidr_summarize(v6_list) + end + + # decide what to return + summarized_list = [] + if (!objectify) + summarized_list = [] + if (v4_summary.length != 0) + v4_summary.each {|x| summarized_list.push(x.desc())} + end + + if (v6_summary.length != 0) + v6_summary.each {|x| summarized_list.push(x.desc(:Short => short))} + end + + else + summarized_list.concat(v4_summary) if (v4_summary.length != 0) + summarized_list.concat(v6_summary) if (v6_summary.length != 0) + end + + return(summarized_list) +end +module_function :merge + +#===Synopsis +#Given the number of IP addresses required in a subnet, return the minimum +#netmask (bits by default) required for that subnet. IP version is assumed to be 4 unless specified otherwise. +# +# Example: +# NetAddr.minimum_size(14) => 28 +# NetAddr.minimum_size(65536, :Version => 6) => 112 +# +#===Arguments: +#* ipcount = IP count as an Integer +#* options = Hash with the following keys: +# :Extended -- If true, then return the netmask, as a String, in extended format (IPv4 only y.y.y.y) +# :Version -- IP version - Integer +# +#===Returns: +#* Integer or String +# +def minimum_size(ipcount, options=nil) + version = 4 + extended = false + known_args = [:Version, :Extended] + + # validate ipcount + raise ArgumentError, "Integer expected for argument 'ipcount' but #{ipcount.class} provided." if (!ipcount.kind_of?(Integer)) + + # validate options + if (options) + raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash)) + + NetAddr.validate_args(options.keys,known_args) + + if (options.has_key?(:Version)) + version = options[:Version] + end + + if (options.has_key?(:Extended) && options[:Extended] == true) + extended = true + end + end + + return( ip_count_to_size(ipcount,version,extended) ) +end +module_function :minimum_size + +#===Synopsis +#Convert IP netmask into an Integer. Netmask may be in either CIDR (/yy) or +#extended (y.y.y.y) format. CIDR formatted netmasks may either +#be a String or an Integer. IP version defaults to 4. It may be necessary +#to specify the version if an IPv6 netmask of /32 or smaller is provided. +# +# Example: +# NetAddr.netmask_to_i('255.255.255.0') => 4294967040 +# NetAddr.netmask_to_i('24') => 4294967040 +# NetAddr.netmask_to_i(24) => 4294967040 +# NetAddr.netmask_to_i('/24') => 4294967040 +# NetAddr.netmask_to_i('32', :Version => 6) => 340282366841710300949110269838224261120 +# +#===Arguments +#* netmask = Netmask as a String or Integer +#* options = Hash with the following keys: +# :Version -- IP version - Integer +# +#===Returns: +#* Integer +# +def netmask_to_i(netmask, options=nil) + known_args = [:Version] + version = 4 + netmask_int = nil + + # validate options + if (options) + raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash)) + NetAddr.validate_args(options.keys,known_args) + + if (options.has_key?(:Version)) + version = options[:Version] + if (version != 4 && version != 6) + raise VersionError, ":Version should be 4 or 6, but was '#{version}'." + end + end + end + + if (netmask.kind_of?(String)) + validate_netmask_str(netmask, version) + netmask_int = netmask_str_to_int(netmask,version) + + elsif (netmask.kind_of?(Integer)) + validate_netmask_int(netmask, version, true) + netmask_int = bits_to_mask(netmask,version) + + else + raise ArgumentError, "String or Integer expected for argument 'netmask', " + + "but #{netmask.class} provided." if (!netmask.kind_of?(Integer) && !netmask.kind_of?(String)) + end + + return(netmask_int) +end +module_function :netmask_to_i + +#===Synopsis +#Given two CIDR addresses or NetAddr::CIDR objects of the same version, +#return all IP addresses between them. NetAddr.range will use the original IP +#address passed during the initialization of the NetAddr::CIDR objects, or the +#IP address portion of any CIDR addresses passed. The default behavior is to be +#non-inclusive (don't include boundaries as part of returned data). +# +# Example: +# lower = NetAddr::CIDR.create('192.168.35.0') +# upper = NetAddr::CIDR.create('192.168.39.255') +# NetAddr.range(lower,upper, :Limit => 10, :Bitstep => 32) +# NetAddr.range('192.168.35.0','192.168.39.255', :Inclusive => true) +# NetAddr.range('192.168.35.0','192.168.39.255', :Inclusive => true, :Size => true) +# +#===Arguments: +#* lower = Lower boundary CIDR as a String or NetAddr::CIDR object +#* upper = Upper boundary CIDR as a String or NetAddr::CIDR object +#* options = Hash with the following keys: +# :Bitstep -- enumerate in X sized steps - Integer +# :Inclusive -- if true, include boundaries in returned data +# :Limit -- limit returned list to X number of items - Integer +# :Objectify -- if true, return CIDR objects +# :Short -- if true, return IPv6 addresses in short-hand notation +# :Size -- if true, return the number of addresses in this range, but not the addresses themselves +# +#===Returns: +#* Array of Strings or NetAddr::CIDR objects, or an Integer +# +#===Note: +#If you do not need all of the fancy options in this method, then please consider +#using the standard Ruby Range class as shown below. +# +# Example: +# start = NetAddr::CIDR.create('192.168.1.0') +# fin = NetAddr::CIDR.create('192.168.2.3') +# (start..fin).each {|addr| puts addr.desc} +# +def range(lower, upper, options=nil) + known_args = [:Bitstep, :Inclusive, :Limit, :Objectify, :Short, :Size] + list = [] + bitstep = 1 + objectify = false + short = false + size_only = false + inclusive = false + limit = nil + + # if lower/upper are not CIDR objects, then attempt to create + # cidr objects from them + if ( !lower.kind_of?(NetAddr::CIDR) ) + begin + lower = NetAddr::CIDR.create(lower) + rescue Exception => error + raise ArgumentError, "Argument 'lower' raised the following " + + "errors: #{error}" + end + end + + if ( !upper.kind_of?(NetAddr::CIDR)) + begin + upper = NetAddr::CIDR.create(upper) + rescue Exception => error + raise ArgumentError, "Argument 'upper' raised the following " + + "errors: #{error}" + end + end + + # validate options + if (options) + raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash)) + NetAddr.validate_args(options.keys,known_args) + + if( options.has_key?(:Bitstep) ) + bitstep = options[:Bitstep] + end + + if( options.has_key?(:Objectify) && options[:Objectify] == true ) + objectify = true + end + + if( options.has_key?(:Short) && options[:Short] == true ) + short = true + end + + if( options.has_key?(:Size) && options[:Size] == true ) + size_only = true + end + + if( options.has_key?(:Inclusive) && options[:Inclusive] == true ) + inclusive = true + end + + if( options.has_key?(:Limit) ) + limit = options[:Limit] + end + end + + # check version, store & sort + if (lower.version == upper.version) + version = lower.version + boundaries = [lower.to_i(:ip), upper.to_i(:ip)] + boundaries.sort + else + raise VersionError, "Provided NetAddr::CIDR objects are of different IP versions." + end + + # dump our range + if (!inclusive) + my_ip = boundaries[0] + 1 + end_ip = boundaries[1] + else + my_ip = boundaries[0] + end_ip = boundaries[1] + 1 + end + + if (!size_only) + until (my_ip >= end_ip) + if (!objectify) + my_ip_s = ip_int_to_str(my_ip, version) + my_ips = shorten(my_ips) if (short && version == 6) + list.push(my_ip_s) + else + list.push( cidr_build(version,my_ip) ) + end + + my_ip = my_ip + bitstep + if (limit) + limit = limit - 1 + break if (limit == 0) + end + end + else + list = end_ip - my_ip + end + + return(list) +end +module_function :range + +#===Synopsis +#Take a standard IPv6 address and format it in short-hand notation. +#The address should not contain a netmask. +# +# Example: +# NetAddr.shorten('fec0:0000:0000:0000:0000:0000:0000:0001') => "fec0::1" +# +#===Arguments: +#* addr = String +# +#===Returns: +#* String +# +def shorten(addr) + + # is this a string? + if (!addr.kind_of? String) + raise ArgumentError, "Expected String, but #{addr.class} provided." + end + + validate_ip_str(addr, 6) + + # make sure this isnt already shorthand + if (addr =~ /::/) + return(addr) + end + + # split into fields + fields = addr.split(":") + + # check last field for ipv4-mapped addr + if (fields.last() =~ /\./ ) + ipv4_mapped = fields.pop() + end + + # look for most consecutive '0' fields + start_field,end_field = nil,nil + start_end = [] + consecutive,longest = 0,0 + + (0..(fields.length-1)).each do |x| + fields[x] = fields[x].to_i(16) + + if (fields[x] == 0) + if (!start_field) + start_field = x + end_field = x + else + end_field = x + end + consecutive += 1 + else + if (start_field) + if (consecutive > longest) + longest = consecutive + start_end = [start_field,end_field] + start_field,end_field = nil,nil + end + consecutive = 0 + end + end + + fields[x] = fields[x].to_s(16) + end + + # if our longest set of 0's is at the end, then start & end fields + # are already set. if not, then make start & end fields the ones we've + # stored away in start_end + if (consecutive > longest) + longest = consecutive + else + start_field = start_end[0] + end_field = start_end[1] + end + + if (longest > 1) + fields[start_field] = '' + start_field += 1 + fields.slice!(start_field..end_field) + end + fields.push(ipv4_mapped) if (ipv4_mapped) + short = fields.join(':') + short << ':' if (short =~ /:$/) + + return(short) +end +module_function :shorten + +#===Synopsis +#Sort a list of CIDR addresses or NetAddr::CIDR objects, +# +# Example: +# cidr1 = NetAddr::CIDR.create('192.168.1.32/27') +# cidr2 = NetAddr::CIDR.create('192.168.1.0/27') +# NetAddr.sort([cidr1,cidr2]) +# NetAddr.sort(['192.168.1.32/27','192.168.1.0/27','192.168.2.0/24'], :Desc => true) +# +#===Arguments: +#* list = Array of CIDR addresses as Strings, or Array of NetAddr::CIDR objects +#* options = Hash with the following keys: +# :ByMask -- if true, sorts based on the netmask length +# :Desc -- if true, return results in descending order +# +#===Returns: +#* Array of Strings, or Array of NetAddr::CIDR objects +# +def sort(list, options=nil) + # make sure list is an array + if ( !list.kind_of?(Array) ) + raise ArgumentError, "Array of NetAddr::CIDR or NetStruct " + + "objects expected, but #{list.class} provided." + end + + desc = false + by_mask = false + # validate options + if (options) + known_args = [:Desc, :ByMask] + raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash)) + NetAddr.validate_args(options.keys,known_args) + + if( options.has_key?(:Desc) && options[:Desc] == true ) + desc = true + end + + if( options.has_key?(:ByMask) && options[:ByMask] == true ) + by_mask = true + end + + end + + # make sure all are valid types of the same IP version + version = nil + cidr_hash = {} + list.each do |cidr| + if (!cidr.kind_of?(NetAddr::CIDR)) + begin + new_cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "An element of the provided Array " + + "raised the following errors: #{error}" + end + else + new_cidr = cidr + end + cidr_hash[new_cidr] = cidr + + version = new_cidr.version if (!version) + unless (new_cidr.version == version) + raise VersionError, "Provided CIDR addresses must all be of the same IP version." + end + end + + # perform sort + if (by_mask) + sorted_list = netmask_sort(cidr_hash.keys, desc) + else + sorted_list = cidr_sort(cidr_hash.keys, desc) + end + + # return original values passed + ret_list = [] + sorted_list.each {|x| ret_list.push(cidr_hash[x])} + + return(ret_list) +end +module_function :sort + +#===Synopsis +#Given a list of CIDR addresses or NetAddr::CIDR objects, +#return only the top-level supernet CIDR addresses. +# +# +#If the :Objectify option is enabled, then returned CIDR objects will +#store the more specific CIDRs (i.e. subnets of those CIDRs) within the tag value :Subnets +#For example, cidr_x.tag[:Subnets] would be an Array of CIDR subnets of cidr_x. +# +# Example: +# NetAddr.supernets(['192.168.0.0', '192.168.0.1', '192.168.0.0/31']) +# +#===Arguments: +#* list = Array of CIDR addresses as Strings, or an Array of NetAddr::CIDR objects +#* options = Hash with the following keys: +# :Objectify -- if true, return NetAddr::CIDR objects +# :Short -- if true, return IPv6 addresses in short-hand notation +# +#===Returns: +#* Array of CIDR addresses or NetAddr::CIDR objects +# +def supernets(list,options=nil) + known_args = [:Objectify, :Short] + short = false + objectify = false + verbose = false + + # validate list + raise ArgumentError, "Array expected for argument 'list' but #{list.class} provided." if (!list.kind_of?(Array) ) + + # validate options + if (options) + raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash) ) + NetAddr.validate_args(options.keys,known_args) + + if (options.has_key?(:Objectify) && options[:Objectify] == true) + objectify = true + end + + if (options.has_key?(:Short) && options[:Short] == true) + short = true + end + end + + # make sure all are valid types of the same IP version + v4_list = [] + v6_list = [] + list.each do |obj| + if (!obj.kind_of?(NetAddr::CIDR)) + begin + obj = NetAddr::CIDR.create(obj) + rescue Exception => error + raise ArgumentError, "One of the provided CIDR addresses raised the following " + + "errors: #{error}" + end + end + + if (obj.version == 4) + v4_list.push(obj) + else + v6_list.push(obj) + end + end + + # do summary calcs + v4_summary = [] + v6_summary = [] + if (v4_list.length != 0) + v4_summary = NetAddr.cidr_supernets(v4_list) + end + + if (v6_list.length != 0) + v6_summary = NetAddr.cidr_supernets(v6_list) + end + + # decide what to return + summarized_list = [] + if (!objectify) + summarized_list = [] + if (v4_summary.length != 0) + v4_summary.each {|x| summarized_list.push(x.desc())} + end + + if (v6_summary.length != 0) + v6_summary.each {|x| summarized_list.push(x.desc(:Short => short))} + end + + else + summarized_list.concat(v4_summary) if (v4_summary.length != 0) + summarized_list.concat(v6_summary) if (v6_summary.length != 0) + end + + return(summarized_list) +end +module_function :supernets + +#===Synopsis +#Take an IPv6 address in short-hand format, and expand it into standard +#notation. The address should not contain a netmask. +# +# Example: +# NetAddr.unshorten('fec0::1') => "fec0:0000:0000:0000:0000:0000:0000:0001" +# +#===Arguments: +#* ip = CIDR address as a String +# +#===Returns: +#* String +# +def unshorten(ip) + + # is this a string? + if (!ip.kind_of? String) + raise ArgumentError, "Expected String, but #{ip.class} provided." + end + + validate_ip_str(ip, 6) + ipv4_mapped = true if (ip =~ /\./) + + ip_int = ip_to_i(ip, :Version => 6) + if (!ipv4_mapped) + long = ip_int_to_str(ip_int, 6) + else + long = ip_int_to_str(ip_int, 6, true) + end + + return(long) +end +module_function :unshorten + +#===Synopsis +#Validate an EUI-48 or EUI-64 address. Raises NetAddr::ValidationError on validation failure. +# +# Example: +# NetAddr.validate_eui('01-00-5e-12-34-56') => true +# +# - Arguments +#* eui = EUI address as a String +# +#===Returns: +#* True +# +def validate_eui(eui) + if (eui.kind_of?(String)) + # check for invalid characters + if (eui =~ /[^0-9a-fA-F\.\-\:]/) + raise ValidationError, "#{eui} is invalid (contains invalid characters)." + end + + # split on formatting characters & check lengths + if (eui =~ /\-/) + fields = eui.split('-') + if (fields.length != 6 && fields.length != 8) + raise ValidationError, "#{eui} is invalid (unrecognized formatting)." + end + fields.each {|x| raise ValidationError, "#{eui} is invalid (missing characters)." if (x.length != 2)} + elsif (eui =~ /\:/) + fields = eui.split(':') + if (fields.length != 6 && fields.length != 8) + raise ValidationError, "#{eui} is invalid (unrecognized formatting)." + end + fields.each {|x| raise ValidationError, "#{eui} is invalid (missing characters)." if (x.length != 2)} + elsif (eui =~ /\./) + fields = eui.split('.') + if (fields.length != 3 && fields.length != 4) + raise ValidationError, "#{eui} is invalid (unrecognized formatting)." + end + fields.each {|x| raise ValidationError, "#{eui} is invalid (missing characters)." if (x.length != 4)} + else + raise ValidationError, "#{eui} is invalid (unrecognized formatting)." + end + + else + raise ArgumentError, "EUI address should be a String, but was a#{eui.class}." + end + return(true) +end +module_function :validate_eui + +#===Synopsis +#Validate an IP address. The address should not contain a netmask. +#This method will attempt to auto-detect the IP version +#if not provided, however a slight speed increase is realized if version is provided. +#Raises NetAddr::ValidationError on validation failure. +# +# Example: +# NetAddr.validate_ip_addr('192.168.1.1') => true +# NetAddr.validate_ip_addr('ffff::1', :Version => 6) => true +# NetAddr.validate_ip_addr('::192.168.1.1') => true +# NetAddr.validate_ip_addr(0xFFFFFF) => true +# NetAddr.validate_ip_addr(2**128-1) => true +# NetAddr.validate_ip_addr(2**32-1, :Version => 4) => true +# +#===Arguments +#* ip = IP address as a String or Integer +#* options = Hash with the following keys: +# :Version -- IP version - Integer (optional) +# +#===Returns: +#* True +# +def validate_ip_addr(ip, options=nil) + known_args = [:Version] + version = nil + + # validate options + if (options) + raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash)) + NetAddr.validate_args(options.keys,known_args) + + if (options.has_key?(:Version)) + version = options[:Version] + if (version != 4 && version != 6) + raise ArgumentError, ":Version should be 4 or 6, but was '#{version}'." + end + end + end + + if ( ip.kind_of?(String) ) + version = NetAddr.detect_ip_version(ip) if (!version) + NetAddr.validate_ip_str(ip,version) + + elsif ( ip.kind_of?(Integer) ) + NetAddr.validate_ip_int(ip,version) + + else + raise ArgumentError, "Integer or String expected for argument 'ip' but " + + "#{ip.class} provided." if (!ip.kind_of?(String) && !ip.kind_of?(Integer)) + end + + return(true) +end +module_function :validate_ip_addr + +#===Synopsis +#Validate IP Netmask. Version defaults to 4 if not specified. +#Raises NetAddr::ValidationError on validation failure. +# +# Examples: +# NetAddr.validate_ip_netmask('/32') => true +# NetAddr.validate_ip_netmask(32) => true +# NetAddr.validate_ip_netmask(0xffffffff, :Integer => true) => true +# +#===Arguments: +#* netmask = Netmask as a String or Integer +#* options = Hash with the following keys: +# :Integer -- if true, the provided Netmask is an Integer mask +# :Version -- IP version - Integer (optional) +# +#===Returns: +#* True +# +def validate_ip_netmask(netmask, options=nil) + known_args = [:Integer, :Version] + is_integer = false + version = 4 + + # validate options + if (options) + raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash)) + NetAddr.validate_args(options.keys,known_args) + + if (options.has_key?(:Integer) && options[:Integer] == true) + is_integer = true + end + + if (options.has_key?(:Version)) + version = options[:Version] + if (version != 4 && version != 6) + raise ArgumentError, ":Version should be 4 or 6, but was '#{version}'." + end + end + end + + # validate netmask + if (netmask.kind_of?(String)) + validate_netmask_str(netmask,version) + elsif (netmask.kind_of?(Integer) ) + validate_netmask_int(netmask,version,is_integer) + else + raise ArgumentError, "Integer or String expected for argument 'netmask' but " + + "#{netmask.class} provided." if (!netmask.kind_of?(String) && !netmask.kind_of?(Integer)) + end + + return(true) +end +module_function :validate_ip_netmask + +#===Synopsis +#Convert a wildcard IP into a valid CIDR address. Wildcards must always be at +#the end of the address. Any data located after the first wildcard will be lost. +#Shorthand notation is prohibited for IPv6 addresses. +#IPv6 encoded IPv4 addresses are not currently supported. +# +# Examples: +# NetAddr.wildcard('192.168.*') +# NetAddr.wildcard('192.168.1.*') +# NetAddr.wildcard('fec0:*') +# NetAddr.wildcard('fec0:1:*') +# +#===Arguments: +#* ip = Wildcard IP address as a String +# +#===Returns: +#* CIDR object +# +def wildcard(ip) + version = 4 + + # do operations per version of address + if (ip =~ /\./ && ip !~ /:/) + octets = [] + mask = 0 + + ip.split('.').each do |x| + if (x =~ /\*/) + break + end + octets.push(x) + end + + octets.length.times do + mask = mask << 8 + mask = mask | 0xff + end + + until (octets.length == 4) + octets.push('0') + mask = mask << 8 + end + ip = octets.join('.') + + elsif (ip =~ /:/) + version = 6 + fields = [] + mask = 0 + + raise ArgumentError, "IPv6 encoded IPv4 addresses are unsupported." if (ip =~ /\./) + raise ArgumentError, "Shorthand IPv6 addresses are unsupported." if (ip =~ /::/) + + ip.split(':').each do |x| + if (x =~ /\*/) + break + end + fields.push(x) + end + + fields.length.times do + mask = mask << 16 + mask = mask | 0xffff + end + + until (fields.length == 8) + fields.push('0') + mask = mask << 16 + end + ip = fields.join(':') + end + + # make & return cidr + cidr = cidr_build( version, ip_str_to_int(ip,version), mask ) + + return(cidr) +end +module_function :wildcard + + + + +end # module NetAddr + +__END__ + diff --git a/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/netaddr.rb b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/netaddr.rb new file mode 100644 index 00000000000..f4fc26379d0 --- /dev/null +++ b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/netaddr.rb @@ -0,0 +1,24 @@ +require 'time' +require 'digest/sha1' +require File.join(File.dirname(__FILE__), 'validation_shortcuts.rb') +require File.join(File.dirname(__FILE__), 'ip_math.rb') +require File.join(File.dirname(__FILE__), 'cidr_shortcuts.rb') +require File.join(File.dirname(__FILE__), 'methods.rb') +require File.join(File.dirname(__FILE__), 'cidr.rb') +require File.join(File.dirname(__FILE__), 'tree.rb') +require File.join(File.dirname(__FILE__), 'eui.rb') + +module NetAddr + + class BoundaryError < StandardError #:nodoc: + end + + class ValidationError < StandardError #:nodoc: + end + + class VersionError < StandardError #:nodoc: + end + +end # module NetAddr + +__END__ diff --git a/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/tree.rb b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/tree.rb new file mode 100644 index 00000000000..e90eef37192 --- /dev/null +++ b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/tree.rb @@ -0,0 +1,816 @@ +module NetAddr + +#=Tree +# +#A class & series of methods for creating and manipulating IP-based +#heirarchical trees. Both IPv4 and IPv6 are supported. +# +#A sample tree would look like: +# 192.168.1.0/24 +# 192.168.1.0/26 +# 192.168.1.0/27 +# 192.168.1.0/28 +# 192.168.1.16/29 +# 192.168.1.16/30 +# 192.168.1.24/30 +# 192.168.1.25/32 +# 192.168.1.28/30 +# 192.168.1.32/27 +# 192.168.1.64/26 +# 192.168.1.64/27 +# 192.168.1.128/26 +# 192.168.1.192/26 +# +class Tree + +#===Synopsis +#Create a new Tree object. +# +# Example: +# NetAddr::Tree.new() +# +#===Arguments: +#* none +# + def initialize() + # root of our ordered IP tree + @v4_root = NetAddr::CIDRv4.new(0,0,{:Subnets => []}) + @v6_root = NetAddr::CIDRv6.new(0,0,{:Subnets => []}) + end + +#===Synopsis +# Add a CIDR address or NetAddr::CIDR object to the tree. +# Example: +# tree.add!('192.168.1.0/24') +# cidr = NetAddr::CIDR.create('192.168.1.0/24', :Tag => {:title => 'test net'} +# tree.add!(cidr) +# +#===Arguments: +#* String or NetAddr::CIDR object +# +#===Returns: +#* nil +# + def add!(new) + # validate object + if ( !new.kind_of?(NetAddr::CIDR) ) + begin + cidr = NetAddr::CIDR.create(new) + rescue Exception => error + raise ArgumentError, "Provided argument raised the following " + + "errors: #{error}" + end + else + cidr = new.dup + end + + cidr.tag[:Subnets] = [] + add_to_tree(cidr) + + return(nil) + end + +#===Synopsis +# Returns all the ancestors of the provided CIDR addresses. +# +# Example: +# tree.ancestors('192.168.1.0/27') +# +#===Arguments: +#* String or NetAddr::CIDR object +# +#===Returns: +#* Array of NetAddr::CIDR objects +# + def ancestors(cidr) + # validate object + if ( !cidr.kind_of?(NetAddr::CIDR) ) + begin + cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "Provided argument raised the following " + + "errors: #{error}" + end + end + + list = [] + parent = find_parent(cidr) + until (!parent.tag[:Parent]) + list.push( NetAddr.cidr_build(parent.version, parent.to_i(:network), parent.to_i(:netmask)) ) + parent = parent.tag[:Parent] + end + + return(list) + end + +#===Synopsis +# Returns all the immediate children of the provided CIDR addresses. +# +# Example: +# tree.children('192.168.1.0/24') +# +#===Arguments: +#* String or NetAddr::CIDR object +# +#===Returns: +#* Array of NetAddr::CIDR objects +# + def children(cidr) + # validate object + if ( !cidr.kind_of?(NetAddr::CIDR) ) + begin + cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "Provided argument raised the following " + + "errors: #{error}" + end + end + + list = [] + me = find_me(cidr) + if (me) + me.tag[:Subnets].each do |child| + list.push( NetAddr.cidr_build(child.version, child.to_i(:network), child.to_i(:netmask)) ) + end + end + + return(list) + end + +#===Synopsis +# Return all descendants of the provided CIDR address. +# +# Example: +# tree.descendants('192.168.1.0/24') +# +#===Arguments: +#* String or NetAddr::CIDR object +# +#===Returns: +#* Array of NetAddr::CIDR objects +# + def descendants(cidr) + list = [] + + # validate object + if ( !cidr.kind_of?(NetAddr::CIDR) ) + begin + cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "Provided argument raised the following " + + "errors: #{error}" + end + end + + me = find_me(cidr) + if (me) + dump_children(me).each do |x| + child = x[:CIDR] + list.push( NetAddr.cidr_build(child.version, child.to_i(:network), child.to_i(:netmask)) ) + end + end + + return(list) + end + +#===Synopsis +# Remove the provided CIDR address from the tree. +# +# Example: +# tree.remove!('192.168.1.0/24') +# +#===Arguments: +#* String or NetAddr::CIDR object +# +#===Returns: +#* true on success or false on fail +# + def delete!(cidr) + removed = false + + # validate object + if ( !cidr.kind_of?(NetAddr::CIDR) ) + begin + cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "Provided argument raised the following " + + "errors: #{error}" + end + end + + # find matching + me = find_me(cidr) + + # remove + if (me) + parent = me.tag[:Parent] + children = me.tag[:Subnets] + parent.tag[:Subnets].delete(me) + children.each {|x| add_to_parent(x,parent)} + removed = true + end + + return(removed) + end + +#===Synopsis +# Dump the contents of this tree. +# +# Example: +# tree.dump() +# +#===Arguments: +#* none +# +#===Returns: +#* ordered array of hashes with the following fields: +# :CIDR => NetAddr::CIDR object +# :Depth => (depth level in tree) +# + def dump() + list = dump_children(@v4_root) + list.concat( dump_children(@v6_root) ) + list.each {|x| x[:CIDR] = NetAddr.cidr_build(x[:CIDR].version, x[:CIDR].to_i(:network), x[:CIDR].to_i(:netmask)) } + return(list) + end + +#===Synopsis +# Has a CIDR address already been added to the tree? +# +# Example: +# tree.exists?('192.168.1.0/24') +# +#===Arguments: +#* String or NetAddr::CIDR object +# +#===Returns: +#* true or false +# + def exists?(cidr) + found = false + + # validate object + if ( !cidr.kind_of?(NetAddr::CIDR) ) + begin + cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "Provided argument raised the following " + + "errors: #{error}" + end + end + + found = true if (find_me(cidr)) + return(found) + end + +#===Synopsis +# Fill in the missing subnets of a particular CIDR. +# +# Example: +# tree.fill_in!('192.168.1.0/24') +# +#===Arguments: +#* String or NetAddr::CIDR object +# +#===Returns: +#* true or false +# + def fill_in!(cidr) + filled = false + + # validate object + if ( !cidr.kind_of?(NetAddr::CIDR) ) + begin + cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "Provided argument raised the following " + + "errors: #{error}" + end + end + + me = find_me(cidr) + if (me && me.tag[:Subnets].length != 0) + me.tag[:Subnets] = NetAddr.cidr_fill_in(me, me.tag[:Subnets]) + me.tag[:Subnets].each do |subnet| + subnet.tag[:Subnets] = [] if (!subnet.tag.has_key?(:Subnets)) + end + filled = true + end + return(filled) + end + +#===Synopsis +# Find and return a CIDR from within the tree. +# +# Example: +# tree.find('192.168.1.0/24') +# +#===Arguments: +#* String or NetAddr::CIDR object +# +#===Returns: +#* NetAddr::CIDR object, or nil +# + def find(cidr) + if ( !cidr.kind_of?(NetAddr::CIDR) ) + begin + cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "Provided argument raised the following " + + "errors: #{error}" + end + end + + me = find_me(cidr) + if (me) + me = NetAddr.cidr_build(me.version, me.to_i(:network), me.to_i(:netmask)) + end + + return(me) + end + +#===Synopsis +# Find subnets that are of at least size X. Only subnets that are not themselves +# subnetted will be returned. :Subnet takes precedence over :IPCount +# +# Example: +# tree.find_space(:IPCount => 16) +# +#===Arguments: +#* Minimum subnet size in bits, or a Hash with the following keys: +# :Subnet - minimum subnet size in bits for returned subnets +# :IPCount - minimum IP count per subnet required for returned subnets +# :Version - restrict results to IPvX +# +#===Returns: +#* Array of NetAddr::CIDR objects +# + def find_space(options) + known_args = [:Subnet, :IPCount, :Version] + version = nil + if (options.kind_of? Integer) + bits4 = options + bits6 = options + elsif (options.kind_of? Hash) + NetAddr.validate_args(options.keys,known_args) + if (options.has_key?(:Version)) + version = options[:Version] + raise "IP version should be 4 or 6, but was #{version}." if (version != 4 && version !=6) + end + + if (options.has_key?(:Subnet)) + bits4 = options[:Subnet] + bits6 = options[:Subnet] + elsif(options.has_key?(:IPCount)) + bits4 = NetAddr.minimum_size(options[:IPCount], :Version => 4) + bits6 = NetAddr.minimum_size(options[:IPCount], :Version => 6) + else + raise "Missing arguments: :Subnet/:IPCount" + end + else + raise "Integer or Hash expected, but #{options.class} provided." + end + + list = [] + if (!version || version == 4) + dump_children(@v4_root).each do |entry| + cidr = entry[:CIDR] + if ( (cidr.tag[:Subnets].length == 0) && (cidr.bits <= bits4) ) + list.push(cidr) + end + end + end + + if (!version || version == 6) + dump_children(@v6_root).each do |entry| + cidr = entry[:CIDR] + if ( (cidr.tag[:Subnets].length == 0) && (cidr.bits <= bits6) ) + list.push(cidr) + end + end + end + + new_list = [] + list.each {|x| new_list.push( NetAddr.cidr_build(x.version, x.to_i(:network), x.to_i(:netmask)) )} + + return(new_list) + end + +#===Synopsis +#Find the longest matching branch of our tree to which a +#CIDR address belongs. Useful for performing 'routing table' style lookups. +# +# Example: +# tree.longest_match('192.168.1.1') +# +#===Arguments: +#* String or NetAddr::CIDR object +# +#===Returns: +#* NetAddr::CIDR object +# + def longest_match(cidr) + if ( !cidr.kind_of?(NetAddr::CIDR) ) + begin + cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "Provided argument raised the following " + + "errors: #{error}" + end + end + + found = find_me(cidr) + found = find_parent(cidr) if !found + + return( NetAddr.cidr_build(found.version, found.to_i(:network), found.to_i(:netmask)) ) + end + +#===Synopsis +# Remove all subnets of the provided CIDR address. +# +# Example: +# tree.prune!('192.168.1.0/24') +# +#===Arguments: +#* String or NetAddr::CIDR object +# +#===Returns: +#* true on success or false on fail +# + def prune!(cidr) + pruned = false + + # validate object + if ( !cidr.kind_of?(NetAddr::CIDR) ) + begin + cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "Provided argument raised the following " + + "errors: #{error}" + end + end + + me = find_me(cidr) + + if (me) + me.tag[:Subnets].clear + pruned = true + end + + return(pruned) + end + +#===Synopsis +# Remove the provided CIDR address, and all of its subnets from the tree. +# +# Example: +# tree.remove!('192.168.1.0/24') +# +#===Arguments: +#* String or NetAddr::CIDR object +# +#===Returns: +#* true on success or false on fail +# + def remove!(cidr) + removed = false + found = nil + + # validate object + if ( !cidr.kind_of?(NetAddr::CIDR) ) + begin + cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "Provided argument raised the following " + + "errors: #{error}" + end + end + + me = find_me(cidr) + + if (me) + parent = me.tag[:Parent] + parent.tag[:Subnets].delete(me) + removed = true + end + + return(removed) + end + +#===Synopsis +# Resize the provided CIDR address. +# +# Example: +# tree.resize!('192.168.1.0/24', 23) +# +#===Arguments: +#* CIDR address as a String or an NetAddr::CIDR object +#* Integer representing the bits of the new netmask +# +#===Returns: +#* true on success or false on fail +# + def resize!(cidr,bits) + resized = false + + # validate cidr + if ( !cidr.kind_of?(NetAddr::CIDR) ) + begin + cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "Provided argument raised the following " + + "errors: #{error}" + end + end + + me = find_me(cidr) + + if (me) + new = me.resize(bits) + delete!(me) + add!(new) + resized = true + end + + return(resized) + end + +#===Synopsis +# Returns the root of the provided CIDR address. +# +# Example: +# tree.root('192.168.1.32/27') +# +#===Arguments: +#* String or NetAddr::CIDR object +# +#===Returns: +#* NetAddr::CIDR object +# + def root(cidr) + # validate object + if ( !cidr.kind_of?(NetAddr::CIDR) ) + begin + cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "Provided argument raised the following " + + "errors: #{error}" + end + end + + parent = find_parent(cidr) + if (parent.tag.has_key?(:Parent)) # if parent is not 0/0 + while(1) + grandparent = parent.tag[:Parent] + break if (!grandparent.tag.has_key?(:Parent)) # if grandparent is 0/0 + parent = grandparent + end + end + + return( NetAddr.cidr_build(parent.version, parent.to_i(:network), parent.to_i(:netmask)) ) + end + +#===Synopsis +# Print the tree as a formatted string. +# +# Example: +# tree.show() +# +#===Arguments: +#* none +# +#===Returns: +#* String +# + def show() + printed = "IPv4 Tree\n---------\n" + list4 = dump_children(@v4_root) + list6 = dump_children(@v6_root) + + list4.each do |entry| + cidr = entry[:CIDR] + depth = entry[:Depth] + + if (depth == 0) + indent = "" + else + indent = " " * (depth*3) + end + + printed << "#{indent}#{cidr.desc}\n" + end + + printed << "\n\nIPv6 Tree\n---------\n" if (list6.length != 0) + + list6.each do |entry| + cidr = entry[:CIDR] + depth = entry[:Depth] + + if (depth == 0) + indent = "" + else + indent = " " * (depth*3) + end + + printed << "#{indent}#{cidr.desc(:Short => true)}\n" + end + + return(printed) + end + +#===Synopsis +# Return list of the sibling CIDRs of the provided CIDR address. +# +# Example: +# tree.siblings('192.168.1.0/27') +# +#===Arguments: +#* String or NetAddr::CIDR object +# +#===Returns: +#* Array of NetAddr::CIDR objects +# + def siblings(cidr) + # validate object + if ( !cidr.kind_of?(NetAddr::CIDR) ) + begin + cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "Provided argument raised the following " + + "errors: #{error}" + end + end + + list = [] + find_parent(cidr).tag[:Subnets].each do |entry| + if (!cidr.cmp(entry)) + list.push( NetAddr.cidr_build(entry.version, entry.to_i(:network), entry.to_i(:netmask)) ) + end + end + + return(list) + end + +#===Synopsis +# Summarize all subnets of the provided CIDR address. The subnets will be +# placed under the new summary address within the tree. +# +# Example: +# tree.summarize_subnets!('192.168.1.0/24') +# +#===Arguments: +#* String or NetAddr::CIDR object +# +#===Returns: +#* true on success or false on fail +# + def summarize_subnets!(cidr) + merged = false + + # validate object + if ( !cidr.kind_of?(NetAddr::CIDR) ) + begin + cidr = NetAddr::CIDR.create(cidr) + rescue Exception => error + raise ArgumentError, "Provided argument raised the following " + + "errors: #{error}" + end + end + + me = find_me(cidr) + + if (me) + merged = NetAddr.cidr_summarize(me.tag[:Subnets]) + me.tag[:Subnets] = merged + merged = true + end + + return(merged) + end + alias :merge_subnets! :summarize_subnets! + +#===Synopsis +# Return list of the top-level supernets of this tree. +# +# Example: +# tree.supernets() +# +#===Arguments: +#* none +# +#===Returns: +#* Array of NetAddr::CIDR objects +# + def supernets() + supernets = [] + @v4_root.tag[:Subnets].each {|x| supernets.push( NetAddr.cidr_build(x.version, x.to_i(:network), x.to_i(:netmask)) )} + @v6_root.tag[:Subnets].each {|x| supernets.push( NetAddr.cidr_build(x.version, x.to_i(:network), x.to_i(:netmask)) )} + return (supernets) + end + + + + +private + +# Add NetStruct object to an array of NetStruct's +# + def add_to_parent(cidr, parent) + duplicate = false + duplicate = true if (NetAddr.cidr_find_in_list(cidr,parent.tag[:Subnets]).kind_of?(Integer)) + + if (!duplicate) + # check parent for subnets of cidr + new_parent_subs = [] + parent.tag[:Subnets].length.times do + old_cidr = parent.tag[:Subnets].shift + cmp = NetAddr.cidr_compare(cidr, old_cidr) + if (cmp && cmp == 1) + old_cidr.tag[:Parent] = cidr + cidr.tag[:Subnets].push(old_cidr) + else + new_parent_subs.push(old_cidr) + end + end + + cidr.tag[:Parent] = parent + parent.tag[:Subnets] = new_parent_subs + parent.tag[:Subnets].push(cidr) + parent.tag[:Subnets] = NetAddr.cidr_sort(parent.tag[:Subnets]) + end + + return(nil) + end + +# Add CIDR to a Tree +# + def add_to_tree(cidr,root=nil) + parent = find_parent(cidr) + add_to_parent(cidr,parent) + + return(nil) + end + +# Dump contents of an Array of NetStruct objects +# + def dump_children(parent,depth=0) + list = [] + + parent.tag[:Subnets].each do |entry| + list.push({:CIDR => entry, :Depth => depth}) + + if (entry.tag[:Subnets].length > 0) + list.concat( dump_children(entry, (depth+1) ) ) + end + end + + return(list) + end + +# Find the NetStruct to which a cidr belongs. +# + def find_me(cidr) + me = nil + root = nil + if (cidr.version == 4) + root = @v4_root + else + root = @v6_root + end + + # find matching + parent = find_parent(cidr,root) + index = NetAddr.cidr_find_in_list(cidr,parent.tag[:Subnets]) + me = parent.tag[:Subnets][index] if (index.kind_of?(Integer)) + + return(me) + end + +# Find the parent NetStruct to which a child NetStruct belongs. +# + def find_parent(cidr,parent=nil) + if (!parent) + if (cidr.version == 4) + parent = @v4_root + else + parent = @v6_root + end + end + bit_diff = cidr.bits - parent.bits + + # if bit_diff greater than 1 bit then check if one of the children is the actual parent. + if (bit_diff > 1 && parent.tag[:Subnets].length != 0) + list = parent.tag[:Subnets] + found = NetAddr.cidr_find_in_list(cidr,list) + if (found.kind_of?(NetAddr::CIDR)) + parent = find_parent(cidr,found) + end + end + + return(parent) + end + +end # class Tree + +end # module NetAddr +__END__ diff --git a/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/validation_shortcuts.rb b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/validation_shortcuts.rb new file mode 100644 index 00000000000..925b1835260 --- /dev/null +++ b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/lib/validation_shortcuts.rb @@ -0,0 +1,201 @@ +module NetAddr +private + +# validate options hash +# +def validate_args(to_validate,known_args) + to_validate.each do |x| + raise ArgumentError, "Unrecognized argument #{x}. Valid arguments are " + + "#{known_args.join(',')}" if (!known_args.include?(x)) + end +end +module_function :validate_args + +def validate_ip_int(ip,version) + version = 4 if (!version && ip < 2**32) + if (version == 4) + raise ValidationError, "#{ip} is invalid for IPv4 (Integer is out of bounds)." if ( (ip < 0) || (ip > 2**32-1) ) + else + raise ValidationError, "#{ip} is invalid for both IPv4 and IPv6 (Integer is out of bounds)." if ( (ip < 0) || (ip > 2**128-1) ) + version = 6 + end + return(version) +end +module_function :validate_ip_int + +def validate_ip_str(ip,version) + # check validity of charaters + if (ip =~ /[^0-9a-fA-F\.:]/) + raise ValidationError, "#{ip} is invalid (contains invalid characters)." + end + + if (version == 4) + octets = ip.split('.') + raise ValidationError, "#{ip} is invalid (IPv4 requires (4) octets)." if (octets.length != 4) + + # are octets in range 0..255? + octets.each do |octet| + raise ValidationError, "#{ip} is invalid (IPv4 dotted-decimal format " + + "should not contain non-numeric characters)." if (octet =~ /[\D]/ || octet == '') + octet = octet.to_i() + if ( (octet < 0) || (octet >= 256) ) + raise ValidationError, "#{ip} is invalid (IPv4 octets should be between 0 and 255)." + end + end + + else + # make sure we only have at most (2) colons in a row, and then only + # (1) instance of that + if ( (ip =~ /:{3,}/) || (ip.split("::").length > 2) ) + raise ValidationError, "#{ip} is invalid (IPv6 field separators (:) are bad)." + end + + # set flags + shorthand = false + if (ip =~ /\./) + dotted_dec = true + else + dotted_dec = false + end + + # split up by ':' + fields = [] + if (ip =~ /::/) + shorthand = true + ip.split('::').each do |x| + fields.concat( x.split(':') ) + end + else + fields.concat( ip.split(':') ) + end + + # make sure we have the correct number of fields + if (shorthand) + if ( (dotted_dec && fields.length > 6) || (!dotted_dec && fields.length > 7) ) + raise ValidationError, "#{ip} is invalid (IPv6 shorthand notation has " + + "incorrect number of fields)." + end + else + if ( (dotted_dec && fields.length != 7 ) || (!dotted_dec && fields.length != 8) ) + raise ValidationError, "#{ip} is invalid (IPv6 address has " + + "incorrect number of fields)." + end + end + + # if dotted_dec then validate the last field + if (dotted_dec) + dotted = fields.pop() + octets = dotted.split('.') + raise ValidationError, "#{ip} is invalid (Legacy IPv4 portion of IPv6 " + + "address should contain (4) octets)." if (octets.length != 4) + octets.each do |x| + raise ValidationError, "#{ip} is invalid (egacy IPv4 portion of IPv6 " + + "address should not contain non-numeric characters)." if (x =~ /[^0-9]/ ) + x = x.to_i + if ( (x < 0) || (x >= 256) ) + raise ValidationError, "#{ip} is invalid (Octets of a legacy IPv4 portion of IPv6 " + + "address should be between 0 and 255)." + end + end + end + + # validate hex fields + fields.each do |x| + if (x =~ /[^0-9a-fA-F]/) + raise ValidationError, "#{ip} is invalid (IPv6 address contains invalid hex characters)." + else + x = x.to_i(16) + if ( (x < 0) || (x >= 2**16) ) + raise ValidationError, "#{ip} is invalid (Fields of an IPv6 address " + + "should be between 0x0 and 0xFFFF)." + end + end + end + + end + return(true) +end +module_function :validate_ip_str + +def validate_netmask_int(netmask,version,is_int=false) + address_len = 32 + address_len = 128 if (version == 6) + + if (!is_int) + if (netmask > address_len || netmask < 0 ) + raise ValidationError, "Netmask, #{netmask}, is out of bounds for IPv#{version}." + end + else + if (netmask >= 2**address_len || netmask < 0 ) + raise ValidationError, "netmask (#{netmask}) is out of bounds for IPv#{version}." + end + end + return(true) +end +module_function :validate_netmask_int + +def validate_netmask_str(netmask,version) + address_len = 32 + address_len = 128 if (version == 6) + + if(netmask =~ /\./) # extended netmask + all_f = 2**32-1 + netmask_int = 0 + + # validate & pack extended mask + begin + netmask_int = NetAddr.ip_to_i(netmask, :Version => 4) + rescue Exception => error + raise ValidationError, "#{netmask} is improperly formed: #{error}" + end + + # cycle through the bits of hostmask and compare + # with netmask_int. when we hit the firt '1' within + # netmask_int (our netmask boundary), xor hostmask and + # netmask_int. the result should be all 1's. this whole + # process is in place to make sure that we dont have + # and crazy masks such as 255.254.255.0 + hostmask = 1 + 32.times do + check = netmask_int & hostmask + if ( check != 0) + hostmask = hostmask >> 1 + unless ( (netmask_int ^ hostmask) == all_f) + raise ValidationError, "#{netmask} contains '1' bits within the host portion of the netmask." + end + break + else + hostmask = hostmask << 1 + hostmask = hostmask | 1 + end + end + + else # cidr format + # remove '/' if present + if (netmask =~ /^\// ) + netmask[0] = " " + netmask.lstrip! + end + + # check if we have any non numeric characters + if (netmask =~ /\D/) + raise ValidationError, "#{netmask} contains invalid characters." + end + + netmask = netmask.to_i + if (netmask > address_len || netmask < 0 ) + raise ValidationError, "Netmask, #{netmask}, is out of bounds for IPv#{version}." + end + + end + return(true) +end +module_function :validate_netmask_str + + + +end # module NetAddr + +__END__ + + diff --git a/src/vendor/cache/netaddr-rb-c7a7de39b7e1/license b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/license new file mode 100644 index 00000000000..3aa0ef9cf8e --- /dev/null +++ b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/license @@ -0,0 +1,13 @@ +Copyright Dustin L. Spinhirne + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/src/vendor/cache/netaddr-rb-c7a7de39b7e1/netaddr.gemspec b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/netaddr.gemspec new file mode 100644 index 00000000000..673d9dce431 --- /dev/null +++ b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/netaddr.gemspec @@ -0,0 +1,19 @@ +# -*- encoding: utf-8 -*- +# stub: netaddr 1.5.3 ruby lib + +Gem::Specification.new do |s| + s.name = "netaddr".freeze + s.version = "1.5.3" + + s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= + s.require_paths = ["lib".freeze] + s.authors = ["Dustin Spinhirne".freeze] + s.date = "2021-10-07" + s.extra_rdoc_files = ["README.md".freeze, "Errors".freeze, "changelog".freeze, "license".freeze] + s.files = ["Errors".freeze, "README.md".freeze, "changelog".freeze, "lib/cidr.rb".freeze, "lib/cidr_shortcuts.rb".freeze, "lib/eui.rb".freeze, "lib/ip_math.rb".freeze, "lib/methods.rb".freeze, "lib/netaddr.rb".freeze, "lib/tree.rb".freeze, "lib/validation_shortcuts.rb".freeze, "license".freeze, "test/cidr_test.rb".freeze, "test/eui_test.rb".freeze, "test/methods_test.rb".freeze, "test/tree_test.rb".freeze] + s.licenses = ["Apache-2.0".freeze] + s.rubygems_version = "3.3.3".freeze + s.summary = "A package for manipulating network addresses.".freeze + + s.installed_by_version = "3.3.3" if s.respond_to? :installed_by_version +end diff --git a/src/vendor/cache/netaddr-rb-c7a7de39b7e1/test/cidr_test.rb b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/test/cidr_test.rb new file mode 100644 index 00000000000..4ce81bbb70f --- /dev/null +++ b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/test/cidr_test.rb @@ -0,0 +1,545 @@ +#!/usr/bin/ruby + +#require 'lib/netaddr.rb' +require_relative "../lib/netaddr.rb" +require 'test/unit' + + + +class TestCIDR < Test::Unit::TestCase + + + def test_new + cidr = NetAddr::CIDRv4.new(3232235777, netmask=4294967040, tag={}, wildcard_mask=4294967040) + assert_equal('192.168.1.0/24', cidr.desc) + assert_equal('192.168.1.1', cidr.ip) + assert_equal('255.255.255.0', cidr.wildcard_mask) + end + + def test_create + assert_raise(ArgumentError) {NetAddr::CIDR.create('192.168.1.0/24', :test => true)} + assert_nothing_raised(Exception){NetAddr::CIDR.create('0.0.0.0/0')} + assert_nothing_raised(Exception){NetAddr::CIDR.create('192.168.1.0/24')} + assert_nothing_raised(Exception){NetAddr::CIDR.create('192.168.1.0/24') } + assert_nothing_raised(Exception){NetAddr::CIDR.create('192.168.1.0 255.255.255.0')} + assert_nothing_raised(Exception){NetAddr::CIDR.create('192.168.1.1') } + assert_nothing_raised(Exception){NetAddr::CIDR.create('192.168.1.1 ') } + assert_nothing_raised(Exception){NetAddr::CIDR.create('fec0::/64') } + assert_nothing_raised(Exception){NetAddr::CIDR.create('192.168.1.1/24 255.255.0.0')} + assert_nothing_raised(Exception){NetAddr::CIDR.create('::/0')} + assert_nothing_raised(Exception){NetAddr::CIDR.create('fec0::1/64')} + assert_nothing_raised(Exception){NetAddr::CIDR.create('fec0::1/64')} + assert_nothing_raised(Exception){NetAddr::CIDR.create(0x0a0a0a0a, :Mask => 0xffffffff)} + assert_nothing_raised(Exception){NetAddr::CIDR.create('192.168.1.1', :WildcardMask => ['0.0.7.255', true]) } + assert_nothing_raised(Exception){NetAddr::CIDR.create('192.168.1.1', :WildcardMask => [0x000007ff, true]) } + assert_nothing_raised(Exception){NetAddr::CIDR.create('fec0::1', :WildcardMask => ['0000:ffff::ffff', true])} + assert_nothing_raised(Exception){NetAddr::CIDR.create('fec0::1', :WildcardMask => [0xffff, true])} + + assert_kind_of(NetAddr::CIDRv4, NetAddr::CIDR.create('192.168.1.1 255.255.0.0')) + assert_kind_of(NetAddr::CIDRv4, NetAddr::CIDR.create('192.168.1.1/24 255.255.0.0')) + assert_kind_of(NetAddr::CIDRv6, NetAddr::CIDR.create('fec0::1/64')) + assert_kind_of(NetAddr::CIDRv4, NetAddr::CIDR.create('10.10.10.10/32 255.255.255.0')) + assert_kind_of(NetAddr::CIDRv4, NetAddr::CIDR.create('10.10.10.10/32', :Mask => 0xffffff00)) + + assert_raise(ArgumentError){ NetAddr::CIDR.create(:Version => 4) } + assert_raise(NetAddr::ValidationError){ NetAddr::CIDR.create('192.168.1.1', :WildcardMask => ['0000:ffff::ffff', true]) } + assert_raise(NetAddr::ValidationError){ NetAddr::CIDR.create('fec0::1', :WildcardMask => ['0.0.7.255', true]) } + + cidr = NetAddr::CIDRv4.create('192.168.1.1 255.255.0.0') + assert_equal(16, cidr.bits ) + + cidr = NetAddr::CIDRv4.create('192.168.1.1/24 255.255.0.0') + assert_equal(24, cidr.bits ) + + cidr = NetAddr::CIDRv4.create('10.10.10.10/32 255.255.255.0') + assert_equal(32, cidr.bits ) + + cidr = NetAddr::CIDRv4.create('10.10.10.10/32', :Mask => 0xffffff00) + assert_equal(24, cidr.bits ) + + cidr = NetAddr::CIDR.create('fec0::1/64') + assert_equal(64, cidr.bits ) + + assert_raise(ArgumentError){ NetAddr::CIDRv4.create({}) } + assert_raise(NetAddr::ValidationError){ NetAddr::CIDRv4.create('192.168.1.0 a') } + end + + def test_comparasins + cidr4 = NetAddr::CIDR.create('192.168.1.1/24') + + assert(cidr4 == '192.168.1.0/24') + assert(cidr4 > '192.168.0.0/24') + assert(cidr4 < '192.168.2.0/24') + assert_equal(0, cidr4 <=> '192.168.1.0/24') + assert_equal(1, cidr4 <=> '192.168.0.0/24') + assert_equal(-1, cidr4 <=> '192.168.2.0/24') + end + + def test_index + cidr = NetAddr::CIDR.create('192.168.1.0/24') + assert_equal('192.168.1.1/32', cidr[1].desc) + assert_equal('192.168.1.255/32', cidr[255].desc) + assert_raise(NetAddr::BoundaryError){ cidr[256] } + assert_raise(NetAddr::BoundaryError){ cidr[-1] } + assert_raise(ArgumentError){ cidr['a'] } + end + + def test_allocate_allocate_rfc3531 + cidr = NetAddr::CIDR.create('192.168.0.0/16') + centermost = ["192.168.0.0/21", "192.168.32.0/21", "192.168.64.0/21", "192.168.96.0/21", + "192.168.16.0/21", "192.168.48.0/21", "192.168.80.0/21", "192.168.112.0/21", + "192.168.128.0/21", "192.168.144.0/21", "192.168.160.0/21", "192.168.176.0/21", + "192.168.192.0/21", "192.168.208.0/21", "192.168.224.0/21", "192.168.240.0/21", + "192.168.8.0/21", "192.168.24.0/21", "192.168.40.0/21", "192.168.56.0/21", "192.168.72.0/21", + "192.168.88.0/21", "192.168.104.0/21", "192.168.120.0/21", "192.168.136.0/21", + "192.168.152.0/21", "192.168.168.0/21", "192.168.184.0/21", "192.168.200.0/21", + "192.168.216.0/21", "192.168.232.0/21", "192.168.248.0/21"] + leftmost = ["192.168.0.0/21", "192.168.128.0/21", "192.168.64.0/21", "192.168.192.0/21", + "192.168.32.0/21", "192.168.160.0/21", "192.168.96.0/21", "192.168.224.0/21", + "192.168.16.0/21", "192.168.144.0/21", "192.168.80.0/21", "192.168.208.0/21", + "192.168.48.0/21", "192.168.176.0/21", "192.168.112.0/21", "192.168.240.0/21", + "192.168.8.0/21", "192.168.136.0/21", "192.168.72.0/21", "192.168.200.0/21", + "192.168.40.0/21", "192.168.168.0/21", "192.168.104.0/21", "192.168.232.0/21", + "192.168.24.0/21", "192.168.152.0/21", "192.168.88.0/21", "192.168.216.0/21", + "192.168.56.0/21", "192.168.184.0/21", "192.168.120.0/21", "192.168.248.0/21"] + + assert_equal(centermost, cidr.allocate_rfc3531(21, :Strategy => :centermost) ) + assert_equal(leftmost, cidr.allocate_rfc3531(21) ) + assert_equal("192.168.192.0/21", cidr.allocate_rfc3531(21, :Objectify => true)[3].desc ) + assert_equal("192.168.96.0/21", cidr.allocate_rfc3531(21, :Strategy => :centermost, :Objectify => true)[3].desc ) + end + + def test_arpa + cidr4 = NetAddr::CIDR.create('192.168.1.1/24') + cidr6 = NetAddr::CIDR.create('fec0::1/64') + + assert_equal('1.168.192.in-addr.arpa.', cidr4.arpa() ) + assert_equal('0.0.0.0.0.0.0.0.0.0.0.0.0.c.e.f.ip6.arpa.', cidr6.arpa() ) + end + + def test_bits + cidr4 = NetAddr::CIDR.create('192.168.1.1/24') + cidr6 = NetAddr::CIDR.create('fec0::1/64') + assert_equal(24,cidr4.bits() ) + assert_equal(64,cidr6.bits() ) + end + + def test_cmp + + cidr4 = NetAddr::CIDR.create('192.168.1.0/24') + cidr4_2 = NetAddr::CIDR.create('192.168.1.0/26') + cidr6 = NetAddr::CIDR.create('fec0::/64') + cidr6_2 = NetAddr::CIDR.create('fec0::/96') + + assert_equal(1,cidr4.cmp('192.168.1.0/26') ) + assert_equal(-1,cidr4.cmp('192.168.0.0/23') ) + assert_equal(0,cidr4.cmp('192.168.1.0/24') ) + assert_nil(cidr4.cmp('192.168.2.0/26') ) + assert_equal(1,cidr4.cmp(cidr4_2) ) + assert_equal(1,cidr6.cmp('fec0::/96') ) + assert_equal(-1,cidr6.cmp('fec0::/63') ) + assert_equal(0,cidr6.cmp('fec0::/64') ) + assert_nil(cidr6.cmp('fe80::/64') ) + assert_equal(1,cidr6.cmp(cidr6_2) ) + + assert_raise(NetAddr::VersionError) { cidr4.cmp(cidr6_2) } + end + + def test_contains? + + cidr4 = NetAddr::CIDR.create('192.168.1.0/24') + cidr4_2 = NetAddr::CIDR.create('192.168.1.0/26') + cidr6 = NetAddr::CIDR.create('fec0::/64') + cidr6_2 = NetAddr::CIDR.create('fec0::/96') + + assert_equal(true,cidr4.contains?('192.168.1.0/26') ) + assert_equal(true,cidr4.contains?(cidr4_2) ) + assert_equal(true,cidr6.contains?(cidr6_2) ) + assert_equal(false,cidr4.contains?('192.168.2.0/26') ) + assert_equal(false,cidr6.contains?('fe80::/96') ) + + assert_raise(NetAddr::VersionError) { cidr4.contains?(cidr6_2) } + end + + def test_desc + cidr4 = NetAddr::CIDR.create('192.168.1.1/24') + cidr6 = NetAddr::CIDR.create('fec0::1/64') + + assert_raise(ArgumentError) {cidr4.desc(:test => true)} + assert_equal('192.168.1.0/24',cidr4.desc() ) + assert_equal('192.168.1.1/24',cidr4.desc(:IP => true) ) + assert_equal('fec0:0000:0000:0000:0000:0000:0000:0000/64',cidr6.desc() ) + assert_equal('fec0::/64',cidr6.desc(:Short => true) ) + end + + def test_enumerate + cidr4 = NetAddr::CIDR.create('192.168.1.0/24') + cidr6 = NetAddr::CIDR.create('fec0::/64') + + assert_raise(ArgumentError) {cidr4.enumerate(:test => true)} + assert_equal(['192.168.1.0', '192.168.1.1'],cidr4.enumerate(:Limit => 2) ) + assert_equal(['fec0:0000:0000:0000:0000:0000:0000:0000'],cidr6.enumerate(:Limit => 1) ) + assert_equal(['fec0::'],cidr6.enumerate(:Limit => 1, :Short => true) ) + + enums4 = cidr4.enumerate(:Limit => 2, :Bitstep => 5) + enums6 = cidr6.enumerate(:Limit => 2, :Bitstep => 5) + assert_equal('192.168.1.5', enums4[1] ) + assert_equal('fec0:0000:0000:0000:0000:0000:0000:0005', enums6[1] ) + + enums4 = cidr4.enumerate(:Objectify => true,:Limit => 1) + assert_kind_of(NetAddr::CIDR, enums4[0] ) + end + + def test_fill_in + cidr = NetAddr::CIDR.create('192.168.1.0/24') + filled = cidr.fill_in(['192.168.1.0/27','192.168.1.44/30', + '192.168.1.64/26','192.168.1.129']) + + assert_equal(['192.168.1.0/27','192.168.1.32/29','192.168.1.40/30', + '192.168.1.44/30','192.168.1.48/28','192.168.1.64/26', + '192.168.1.128/32','192.168.1.129/32','192.168.1.130/31', + '192.168.1.132/30','192.168.1.136/29','192.168.1.144/28', + '192.168.1.160/27','192.168.1.192/26'],filled) + end + + def test_hostmask_ext + cidr4 = NetAddr::CIDR.create('192.168.1.1/24') + assert_equal('0.0.0.255',cidr4.hostmask_ext() ) + assert_equal('255.255.255.0',cidr4.netmask_ext() ) + end + + def test_ip + cidr4 = NetAddr::CIDR.create('192.168.1.1/24') + cidr6 = NetAddr::CIDR.create('fec0::1/64') + + assert_raise(ArgumentError) {cidr4.ip(:test => true)} + assert_equal('192.168.1.1',cidr4.ip() ) + assert_equal('fec0:0000:0000:0000:0000:0000:0000:0001',cidr6.ip() ) + assert_equal('fec0::1',cidr6.ip(:Short => true) ) + end + + def test_is_contained? + + cidr4 = NetAddr::CIDR.create('192.168.1.0/24') + cidr4_2 = NetAddr::CIDR.create('192.168.1.0/26') + cidr6 = NetAddr::CIDR.create('fec0::/64') + cidr6_2 = NetAddr::CIDR.create('fec0::/96') + + assert_equal(true,cidr4_2.is_contained?('192.168.1.0/24') ) + assert_equal(true,cidr4_2.is_contained?(cidr4) ) + assert_equal(true,cidr6_2.is_contained?('fec0::/64') ) + assert_equal(true,cidr6_2.is_contained?(cidr6) ) + assert_equal(false,cidr4.is_contained?('192.168.2.0/26') ) + assert_equal(false,cidr6.is_contained?('fe80::/96') ) + + assert_raise(NetAddr::VersionError) { cidr4.is_contained?(cidr6_2) } + end + + def test_last + cidr4 = NetAddr::CIDR.create('192.168.1.1/24') + cidr6 = NetAddr::CIDR.create('fec0::1/64') + + assert_raise(ArgumentError) {cidr4.last(:test => true)} + assert_equal('192.168.1.255',cidr4.last() ) + assert_equal('fec0:0000:0000:0000:ffff:ffff:ffff:ffff',cidr6.last() ) + assert_equal('fec0::ffff:ffff:ffff:ffff',cidr6.last(:Short => true) ) + end + + def test_matches? + cidr = NetAddr::CIDR.create('10.0.0.0/24') + assert(cidr.matches?('10.0.0.22')) + assert(!cidr.matches?('10.1.1.1')) + + cidr = NetAddr::CIDR.create('10.0.248.0', :WildcardMask => ['255.248.255.0']) + assert(cidr.matches?('10.1.248.0')) + assert(!cidr.matches?('10.8.248.0')) + + cidr = NetAddr::CIDR.create('10.0.248.0') + cidr.set_wildcard_mask('0.7.0.255', true) + assert(cidr.matches?('10.1.248.0')) + assert(!cidr.matches?('10.8.248.0')) + + cidr = NetAddr::CIDR.create('127.0.0.0') + cidr.set_wildcard_mask('0.255.255.255', true) + assert(cidr.matches?('127.0.0.1')) + assert(!cidr.matches?('128.0.0.0')) + + cidr = NetAddr::CIDR.create('127.0.0.0', :WildcardMask => ['0.255.255.255', true]) + assert(cidr.matches?('127.0.0.1')) + assert(!cidr.matches?('128.0.0.0')) + + cidr = NetAddr::CIDR.create('fec0::1') + cidr.set_wildcard_mask('0000:ffff::ffff', true) + assert(cidr.matches?('fec0:1::1')) + assert(!cidr.matches?('fec0:0:1::1')) + + cidr = NetAddr::CIDR.create('fec0::1', :WildcardMask => ['0000:ffff::ffff', true]) + assert(cidr.matches?('fec0:1::1')) + assert(!cidr.matches?('fec0:0:1::1')) + end + + def test_mcast + cidr4 = NetAddr::CIDR.create('224.0.0.1') + cidr4_2 = NetAddr::CIDR.create('239.255.255.255') + cidr4_3 = NetAddr::CIDR.create('230.2.3.5') + cidr4_4 = NetAddr::CIDR.create('235.147.18.23') + cidr4_5 = NetAddr::CIDR.create('192.168.1.1') + cidr6 = NetAddr::CIDR.create('ff00::1') + cidr6_2 = NetAddr::CIDR.create('ffff::1') + cidr6_3 = NetAddr::CIDR.create('ff00::ffff:ffff') + cidr6_4 = NetAddr::CIDR.create('ff00::fec0:1234:') + cidr6_5 = NetAddr::CIDR.create('2001:4800::1') + + assert_raise(ArgumentError) {cidr4.multicast_mac(:test => true)} + assert_equal('01-00-5e-00-00-01',cidr4.multicast_mac(:Objectify => true).address ) + assert_equal('01-00-5e-7f-ff-ff',cidr4_2.multicast_mac ) + assert_equal('01-00-5e-02-03-05',cidr4_3.multicast_mac ) + assert_equal('01-00-5e-13-12-17',cidr4_4.multicast_mac ) + + assert_equal('33-33-00-00-00-01',cidr6.multicast_mac(:Objectify => true).address ) + assert_equal('33-33-00-00-00-01',cidr6_2.multicast_mac ) + assert_equal('33-33-ff-ff-ff-ff',cidr6_3.multicast_mac ) + assert_equal('33-33-fe-c0-12-34',cidr6_4.multicast_mac ) + + assert_raise(NetAddr::ValidationError){ cidr4_5.multicast_mac } + assert_raise(NetAddr::ValidationError){ cidr6_5.multicast_mac } + end + + def test_netmask + cidr4 = NetAddr::CIDR.create('192.168.1.1/24') + cidr6 = NetAddr::CIDR.create('fec0::1/64') + + assert_equal('/24',cidr4.netmask() ) + assert_equal('/64',cidr6.netmask() ) + end + + def test_netmask_ext + cidr4 = NetAddr::CIDR.create('192.168.1.1/24') + assert_equal('255.255.255.0',cidr4.netmask_ext() ) + end + + def test_network + cidr4 = NetAddr::CIDR.create('192.168.1.1/24') + cidr6 = NetAddr::CIDR.create('fec0::1/64') + + assert_raise(ArgumentError) {cidr4.network(:test => true)} + assert_equal('192.168.1.0',cidr4.network() ) + assert_equal('fec0:0000:0000:0000:0000:0000:0000:0000',cidr6.network() ) + assert_equal('fec0::',cidr6.network(:Short => true) ) + end + + def test_next_ip + cidr4 = NetAddr::CIDR.create('192.168.1.0/24') + cidr6 = NetAddr::CIDR.create('fec0::/64') + + assert_raise(ArgumentError) {cidr4.next_ip(:test => true)} + next4 = cidr4.next_ip() + next6 = cidr6.next_ip() + assert_equal('192.168.2.0',next4 ) + assert_equal('fec0:0000:0000:0001:0000:0000:0000:0000',next6 ) + + next6 = cidr6.next_ip(:Short => true) + assert_equal('fec0:0:0:1::',next6 ) + + next4 = cidr4.next_ip(:Bitstep => 2) + next6 = cidr6.next_ip(:Bitstep => 2) + assert_equal('192.168.2.1',next4 ) + assert_equal('fec0:0000:0000:0001:0000:0000:0000:0001',next6 ) + + next4 = cidr4.next_ip(:Objectify => true) + next6 = cidr6.next_ip(:Objectify => true) + assert_equal('192.168.2.0/32',next4.desc ) + assert_equal('fec0:0000:0000:0001:0000:0000:0000:0000/128',next6.desc ) + + end + + def test_next_subnet + cidr4 = NetAddr::CIDR.create('192.168.1.0/24') + cidr6 = NetAddr::CIDR.create('fec0::/64') + + assert_raise(ArgumentError) {cidr4.next_subnet(:test => true)} + next4 = cidr4.next_subnet() + next6 = cidr6.next_subnet() + assert_equal('192.168.2.0/24',next4 ) + assert_equal('fec0:0000:0000:0001:0000:0000:0000:0000/64',next6 ) + + next6 = cidr6.next_subnet(:Short => true) + assert_equal('fec0:0:0:1::/64',next6 ) + + next4 = cidr4.next_subnet(:Bitstep => 2) + next6 = cidr6.next_subnet(:Bitstep => 2) + assert_equal('192.168.3.0/24',next4 ) + assert_equal('fec0:0000:0000:0002:0000:0000:0000:0000/64',next6 ) + + next4 = cidr4.next_subnet(:Objectify => true) + next6 = cidr6.next_subnet(:Objectify => true) + assert_equal('192.168.2.0/24',next4.desc ) + assert_equal('fec0:0000:0000:0001:0000:0000:0000:0000/64',next6.desc ) + end + + def test_nth + cidr4 = NetAddr::CIDR.create('192.168.1.0/24') + cidr6 = NetAddr::CIDR.create('fec0::/126') + + assert_raise(ArgumentError) {cidr4.nth(1, :test => true)} + assert_equal('192.168.1.1',cidr4.nth(1) ) + assert_equal('192.168.1.50',cidr4.nth(50) ) + assert_kind_of(NetAddr::CIDR,cidr4.nth(1, :Objectify => true) ) + assert_raise(NetAddr::BoundaryError){ cidr4.nth(256) } + assert_raise(ArgumentError){ cidr4.nth() } + + assert_equal('fec0:0000:0000:0000:0000:0000:0000:0001',cidr6.nth(1) ) + assert_equal('fec0:0000:0000:0000:0000:0000:0000:0003',cidr6.nth(3) ) + assert_equal('fec0::1',cidr6.nth(1, :Short => true) ) + assert_raise(NetAddr::BoundaryError){ cidr6.nth(10) } + + assert_raise(ArgumentError) { cidr4.nth({}) } + end + + def test_range + cidr4 = NetAddr::CIDR.create('192.168.1.0/24') + cidr6 = NetAddr::CIDR.create('fec0::/64') + + assert_raise(ArgumentError) {cidr4.range(25,0, :test => true)} + range4 = cidr4.range(25,0, :Bitstep => 5) + range4_2 = cidr4.range(250) + range6 = cidr6.range(25,0, :Bitstep => 5, :Short => true) + + assert_equal(6,range4.length) + assert_equal(6,range4_2.length) + assert_equal(6,range6.length) + assert_equal('192.168.1.0',range4[0]) + assert_equal('192.168.1.25',range4[5]) + assert_equal('fec0::',range6[0]) + assert_equal('fec0::19',range6[5]) + end + + def test_remainder + cidr4 = NetAddr::CIDR.create('192.168.1.0/24') + cidr4_2 = NetAddr::CIDR.create('192.168.1.64/26') + + assert_raise(ArgumentError) {cidr4.remainder(cidr4_2, :test => true)} + remainder = cidr4.remainder(cidr4_2) + + assert_equal(2,remainder.length) + assert_equal('192.168.1.0/26',remainder[0]) + + remainder = cidr4.remainder('192.168.1.64/26', :Objectify => true) + assert_equal('192.168.1.128/25',remainder[1].desc) + end + + def test_resize + cidr4 = NetAddr::CIDR.create('192.168.1.129/24') + cidr6 = NetAddr::CIDR.create('fec0::1/64') + + assert_raise(ArgumentError) {cidr4.resize(23, :test => true)} + new4 = cidr4.resize(23) + new6 = cidr6.resize(63) + assert_equal('192.168.0.0/23',new4.desc ) + assert_equal('fec0::/63',new6.desc(:Short => true) ) + + cidr4.resize!(25) + cidr6.resize!(67) + assert_equal('192.168.1.0/25',cidr4.desc ) + assert_equal('192.168.1.0',cidr4.ip ) + assert_equal('fec0:0000:0000:0000:0000:0000:0000:0000/67',cidr6.desc ) + end + + def test_set_wildcard_mask + cidr = NetAddr::CIDR.create('10.1.0.0/24') + assert_equal('0.0.0.255', cidr.wildcard_mask(true)) + assert_equal('255.255.255.0', cidr.wildcard_mask) + + cidr.set_wildcard_mask('0.7.0.255', true) + assert_equal('0.7.0.255', cidr.wildcard_mask(true)) + assert_equal('255.248.255.0', cidr.wildcard_mask()) + cidr.set_wildcard_mask('255.248.255.0') + assert_equal('0.7.0.255', cidr.wildcard_mask(true)) + assert_equal('255.248.255.0', cidr.wildcard_mask()) + cidr.set_wildcard_mask('0.0.0.0') + assert_equal('0.0.0.0', cidr.wildcard_mask) + assert_raise(NetAddr::ValidationError){ cidr.set_wildcard_mask('0000:ffff::ffff') } + + cidr = NetAddr::CIDR.create('fec0::1/64') + assert_equal('0000:0000:0000:0000:ffff:ffff:ffff:ffff', cidr.wildcard_mask(true)) + cidr.set_wildcard_mask('0000:ffff::ffff', true) + assert_equal('0000:ffff:0000:0000:0000:0000:0000:ffff', cidr.wildcard_mask(true)) + assert_raise(NetAddr::ValidationError){ cidr.set_wildcard_mask('0.7.0.255', true) } + end + + def test_size + cidr4 = NetAddr::CIDR.create('192.168.1.1/24') + cidr6 = NetAddr::CIDR.create('fec0::1/64') + + assert_equal(256,cidr4.size() ) + assert_equal(2**64,cidr6.size() ) + end + + def test_subnet + cidr4 = NetAddr::CIDR.create('192.168.1.0/24') + cidr6 = NetAddr::CIDR.create('fec0::/64') + + assert_raise(ArgumentError) {cidr4.subnet(:test => true)} + subnet4 = cidr4.subnet(:Bits => 26, :NumSubnets => 4) + subnet6 = cidr6.subnet(:Bits => 66, :NumSubnets => 4) + assert_equal('192.168.1.0/26', subnet4[0]) + assert_equal('fec0:0000:0000:0000:0000:0000:0000:0000/66', subnet6[0]) + + subnet4 = cidr4.subnet(:Bits => 26, :NumSubnets => 1) + assert_equal('192.168.1.0/26', subnet4[0]) + assert_equal('192.168.1.64/26', subnet4[1]) + assert_equal('192.168.1.128/25', subnet4[2]) + + subnet4 = cidr4.subnet(:Bits => 28, :NumSubnets => 3, :Objectify => true) + assert_equal('192.168.1.0/28', subnet4[0].desc) + assert_equal('192.168.1.16/28', subnet4[1].desc) + assert_equal('192.168.1.32/28', subnet4[2].desc) + assert_equal('192.168.1.48/28', subnet4[3].desc) + assert_equal('192.168.1.64/26', subnet4[4].desc) + assert_equal('192.168.1.128/25', subnet4[5].desc) + + subnet4 = cidr4.subnet(:IPCount => 112) + assert_equal('192.168.1.0/25', subnet4[0]) + + subnet4 = cidr4.subnet(:IPCount => 31) + assert_equal('192.168.1.0/27', subnet4[0]) + end + + def test_succ + cidr4 = NetAddr::CIDR.create('192.168.1.0/24') + cidr6 = NetAddr::CIDR.create('fec0::/64') + cidr4_2 = NetAddr::CIDR.create('255.255.255.0/24') + + assert_equal('192.168.2.0/24',cidr4.succ.desc) + assert_equal('fec0:0000:0000:0001:0000:0000:0000:0000/64',cidr6.succ.desc ) + assert_raise(NetAddr::BoundaryError) {cidr4_2.succ} + end + + def test_to_i + cidr4 = NetAddr::CIDR.create('192.168.1.1/24') + + assert_equal(3232235776,cidr4.to_i ) + assert_equal(4294967040,cidr4.to_i(:netmask) ) + assert_equal(3232235777,cidr4.to_i(:ip) ) + assert_equal(255,cidr4.to_i(:hostmask) ) + assert_equal(4294967040,cidr4.to_i(:wildcard_mask) ) + end + + def test_unique_local + eui = NetAddr::EUI48.new('abcdef010203') + cidr = NetAddr::CIDR.create('FC00::/7') + assert_kind_of(NetAddr::CIDRv6, NetAddr::CIDRv6.unique_local(eui)) + assert(cidr.contains?(NetAddr::CIDRv6.unique_local(eui)) ) + end + + def test_wildcard_mask + cidr = NetAddr::CIDR.create('10.1.0.0/24', :WildcardMask => ['0.7.0.255', true]) + assert_equal('0.7.0.255', cidr.wildcard_mask(true)) + assert_equal('255.248.255.0', cidr.wildcard_mask) + end + +end + + + + diff --git a/src/vendor/cache/netaddr-rb-c7a7de39b7e1/test/eui_test.rb b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/test/eui_test.rb new file mode 100644 index 00000000000..af562aa5045 --- /dev/null +++ b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/test/eui_test.rb @@ -0,0 +1,101 @@ +#!/usr/bin/ruby + +require_relative "../lib/netaddr.rb" +require 'test/unit' + + + +class TestEUI < Test::Unit::TestCase + + def test_new + assert_not_nil(NetAddr::EUI48.new('aabbccddeeff') ) + assert_not_nil(NetAddr::EUI48.new('aabbccddeeff') ) + assert_not_nil(NetAddr::EUI64.new('aabbccddeeff0001') ) + assert_not_nil(NetAddr::EUI48.new(0x000000000001) ) + assert_not_nil(NetAddr::EUI64.new(0x0000000000000001) ) + + assert_raise(ArgumentError){ NetAddr::EUI48.new() } + assert_raise(ArgumentError){ NetAddr::EUI48.new({}) } + assert_raise(ArgumentError){ NetAddr::EUI64.new() } + assert_raise(ArgumentError){ NetAddr::EUI64.new({}) } + end + + def test_create + assert_not_nil(NetAddr::EUI.create('aa-bb-cc-dd-ee-ff') ) + assert_not_nil(NetAddr::EUI.create('aa:bb:cc:dd:ee:ff') ) + assert_not_nil(NetAddr::EUI.create('aabb.ccdd.eeff') ) + assert_not_nil(NetAddr::EUI.create('aa-bb-cc-dd-ee-ff-00-01') ) + + assert_raise(ArgumentError){ NetAddr::EUI.create() } + assert_raise(ArgumentError){ NetAddr::EUI.create(0x0000000000000001) } + + assert_kind_of(NetAddr::EUI48, NetAddr::EUI.create('aa-bb-cc-dd-ee-ff')) + assert_kind_of(NetAddr::EUI64, NetAddr::EUI.create('aa-bb-cc-dd-ee-ff-00-01')) + end + + def test_simple + mac = NetAddr::EUI.create('aa-bb-cc-dd-ee-ff') + assert_raise(ArgumentError) {mac.oui(:test => true)} + assert_raise(ArgumentError) {mac.ei(:test => true)} + + assert_equal('aa-bb-cc', mac.oui ) + assert_equal('dd-ee-ff', mac.ei ) + assert_equal('aa:bb:cc', mac.oui(:Delimiter => ':' ) ) + assert_equal('dd:ee:ff', mac.ei(:Delimiter => ':' ) ) + assert_equal('aa-bb-cc-dd-ee-ff', mac.address ) + assert_equal('aa:bb:cc:dd:ee:ff', mac.address(:Delimiter => ':') ) + assert_equal('aabb.ccdd.eeff', mac.address(:Delimiter => '.') ) + assert_equal(0xaabbccddeeff, mac.to_i ) + assert_equal(NetAddr::EUI48, mac.class ) + + mac = NetAddr::EUI.create('aa-bb-cc-dd-ee-ff-01-02') + assert_raise(ArgumentError) {mac.oui(:test => true)} + assert_raise(ArgumentError) {mac.ei(:test => true)} + assert_equal('aa-bb-cc', mac.oui ) + assert_equal('dd-ee-ff-01-02', mac.ei ) + assert_equal('aa:bb:cc', mac.oui(:Delimiter => ':') ) + assert_equal('dd:ee:ff:01:02', mac.ei(:Delimiter => ':' ) ) + assert_equal('aa-bb-cc-dd-ee-ff-01-02', mac.address ) + assert_equal('aa:bb:cc:dd:ee:ff:01:02', mac.address(:Delimiter => ':') ) + assert_equal('aabb.ccdd.eeff.0102', mac.address(:Delimiter => '.') ) + assert_equal(0xaabbccddeeff0102, mac.to_i ) + assert_equal(NetAddr::EUI64, mac.class ) + + end + + def test_link_local + mac = NetAddr::EUI.create('aa-bb-cc-dd-ee-ff') + assert_equal('fe80:0000:0000:0000:a8bb:ccff:fedd:eeff', mac.link_local ) + + mac = NetAddr::EUI.create('1234.5678.9abc') + assert_equal('fe80:0000:0000:0000:1034:56ff:fe78:9abc', mac.link_local ) + + mac = NetAddr::EUI.create('1234.5678.9abc.def0') + assert_equal('fe80:0000:0000:0000:1034:5678:9abc:def0', mac.link_local(:Objectify => true).ip ) + assert_raise(ArgumentError) {mac.link_local(:test => true)} + end + + def test_to_eui64 + mac = NetAddr::EUI.create('aa-bb-cc-dd-ee-ff') + assert_equal('aa-bb-cc-ff-fe-dd-ee-ff', mac.to_eui64.address ) + + # check that to_eui64 has no side effects + b = mac.to_eui64 + c = mac.to_eui64 + assert_equal(b.to_s, c.to_s) + end + + def test_to_ipv6 + mac = NetAddr::EUI.create('aa-bb-cc-dd-ee-ff') + assert_equal('fe80:0000:0000:0000:a8bb:ccff:fedd:eeff', mac.to_ipv6('fe80::/64') ) + + mac = NetAddr::EUI.create('1234.5678.9abc') + assert_equal('fe80:0000:0000:0000:1034:56ff:fe78:9abc', mac.to_ipv6('fe80::/64') ) + + mac = NetAddr::EUI.create('1234.5678.9abc.def0') + assert_equal('fe80:0000:0000:0000:1034:5678:9abc:def0', mac.to_ipv6('fe80::/64', :Objectify => true).ip ) + assert_raise(ArgumentError) {mac.link_local(:test => true)} + assert_raise(NetAddr::ValidationError) {mac.to_ipv6('fe80::/65')} + end + +end diff --git a/src/vendor/cache/netaddr-rb-c7a7de39b7e1/test/methods_test.rb b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/test/methods_test.rb new file mode 100644 index 00000000000..6664438eaa9 --- /dev/null +++ b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/test/methods_test.rb @@ -0,0 +1,331 @@ +#!/usr/bin/ruby + +require_relative "../lib/netaddr.rb" +require 'test/unit' + + + +class TestMethods < Test::Unit::TestCase + + def test_i_to_bits + assert_equal(32, NetAddr.i_to_bits(2**32-1) ) + assert_equal(24, NetAddr.i_to_bits((2**32 - 2**8 ) ) ) + assert_equal(128, NetAddr.i_to_bits(2**128-1) ) + assert_equal(96, NetAddr.i_to_bits((2**128 - 2**32)) ) + + assert_raise(ArgumentError){ NetAddr.i_to_bits('1') } + assert_raise(ArgumentError){ NetAddr.i_to_bits({}) } + assert_raise(ArgumentError){ NetAddr.i_to_bits('1')} + end + + def test_i_to_ip + assert_raise(ArgumentError) {NetAddr.i_to_ip(2**32-1, :test => true)} + assert_equal('255.255.255.255', NetAddr.i_to_ip(2**32-1) ) + assert_equal('0.0.0.0', NetAddr.i_to_ip(0, :Version => 4) ) + assert_equal('0000:0000:0000:0000:0000:0000:0000:0000', NetAddr.i_to_ip(0, :Version => 6) ) + assert_equal('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', NetAddr.i_to_ip(2**128-1) ) + assert_equal('0000:0000:0000:0000:0000:0000:ffff:ffff', NetAddr.i_to_ip(2**32-1, :Version => 6) ) + assert_equal('0000:0000:0000:0000:0000:ffff:10.1.0.1', NetAddr.i_to_ip(0xffff0a010001, + :IPv4Mapped => true, + :Version => 6) ) + assert_raise(ArgumentError){ NetAddr.i_to_ip('1') } + assert_raise(ArgumentError){ NetAddr.i_to_ip({}) } + assert_raise(NetAddr::VersionError){ NetAddr.i_to_ip(0xffffffff,:Version => 5) } + assert_raise(ArgumentError){ NetAddr.i_to_ip('1', :Version => 4) } + end + + def test_ip_to_i + assert_raise(ArgumentError) {NetAddr.ip_to_i('255.255.255.255', :test => true)} + assert_equal(2**128-1, NetAddr.ip_to_i('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff') ) + assert_equal(1, NetAddr.ip_to_i('::1') ) + assert_equal(2**32-1, NetAddr.ip_to_i('255.255.255.255') ) + assert_equal(2**128-1, NetAddr.ip_to_i('ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255') ) + assert_equal(0, NetAddr.ip_to_i('::') ) + assert_equal(2**32-1, NetAddr.ip_to_i('::255.255.255.255') ) + assert_equal(0x0a0a0a0a, NetAddr.ip_to_i('10.10.10.10') ) + assert_equal(2**127+1, NetAddr.ip_to_i('8000::0.0.0.1') ) + assert_equal(0x8080000000000000000080800a0a0a0a, NetAddr.ip_to_i('8080::8080:10.10.10.10') ) + assert_equal(0xffff0a010001, NetAddr.ip_to_i('::ffff:10.1.0.1') ) + assert_equal(2**127+1, NetAddr.ip_to_i('8000::1') ) + assert_equal(1, NetAddr.ip_to_i('::1') ) + assert_equal(2**127, NetAddr.ip_to_i('8000::') ) + + assert_raise(ArgumentError){ NetAddr.ip_to_i({}) } + assert_raise(NetAddr::VersionError){ NetAddr.ip_to_i('192.168.1.1',:Version => 5) } + assert_raise(ArgumentError){ NetAddr.ip_to_i(0xffffffff,:Version => 4) } + end + + def test_merge + assert_raise(ArgumentError){ NetAddr.merge(1) } + assert_raise(ArgumentError){ NetAddr.merge({}) } + + subs = NetAddr::CIDR.create('10.0.0.0/24').subnet(:Bits => 26, :Objectify => true) + subs.concat( NetAddr::CIDR.create('10.1.0.0/24').subnet(:Bits => 29, :NumSubnets => 4, :Objectify => true) ) + subs.delete_at(2) + subs.delete_at(7) + assert_equal(['10.0.0.0/25', '10.0.0.192/26', '10.1.0.0/27', '10.1.0.64/26', '10.1.0.128/25'], NetAddr.merge(subs) ) + + cidr = NetAddr::CIDR.create('fec0::/64') + subs = cidr.range(1, 8, :Objectify => true) + subs.concat([NetAddr::CIDR.create('192.168.0.0/27'), NetAddr::CIDR.create('192.168.0.32/27')]) + assert_equal(['192.168.0.0/26', 'fec0::1/128', 'fec0::2/127', 'fec0::4/126', 'fec0::8/128',], NetAddr.merge(subs, :Short => true) ) + + subs = [] + NetAddr.range('192.168.35.0','192.168.39.255', + :Inclusive => true, :Bitstep => 32).each {|x| subs.push(NetAddr::CIDR.create("#{x}/27")) } + assert_equal(['192.168.35.0/24', '192.168.36.0/22'], NetAddr.merge(subs) ) + + subs = NetAddr::CIDR.create('10.0.0.0/24').subnet(:Bits => 26, :Objectify => true) + subs.concat( subs.pop.subnet(:Bits => 27, :Objectify => true) ) + subs.concat( subs.pop.subnet(:Bits => 28, :Objectify => true) ) + subs[5].tag[:test] = true + merged = NetAddr.merge(subs, :Objectify => true) + assert_equal('10.0.0.0/24', merged[0].desc) + assert_equal('10.0.0.240/28', merged[0].tag[:Subnets][5].desc) + assert(merged[0].tag[:Subnets][5].tag[:test]) + + assert_equal(['10.0.0.0/8','192.168.0.0/24'], NetAddr.merge(['10.0.0.0/8', '10.0.0.0/12', '10.0.0.0/24','192.168.0.0/24','192.168.0.64/26']) ) + + end + + def test_minimum_size + assert_raise(ArgumentError) {NetAddr.minimum_size(200, :test => true)} + assert_equal(24, NetAddr.minimum_size(200)) + assert_equal(96, NetAddr.minimum_size(2**32-1, :Version => 6)) + assert_equal('255.255.255.0', NetAddr.minimum_size(200, :Extended => true)) + assert_equal('255.255.255.224', NetAddr.minimum_size(17, :Extended => true)) + assert_equal(24, NetAddr.minimum_size(200, :Extended => false)) + assert_equal(96, NetAddr.minimum_size(2**32-1, :Version => 6, :Extended => true)) + assert_raise(ArgumentError){ NetAddr.minimum_size({}) } + end + + def test_netmask_to_i + assert_raise(ArgumentError) {NetAddr.netmask_to_i('32', :test => true)} + assert_equal(2**32-1, NetAddr.netmask_to_i('255.255.255.255') ) + assert_equal(2**32-1, NetAddr.netmask_to_i('32') ) + assert_equal(2**32-1, NetAddr.netmask_to_i('/32') ) + assert_equal(2**32-1, NetAddr.netmask_to_i(32) ) + assert_equal(2**128-1, NetAddr.netmask_to_i('128', :Version => 6) ) + assert_equal(2**128-1, NetAddr.netmask_to_i('/128', :Version => 6) ) + assert_equal(2**128-1, NetAddr.netmask_to_i(128, :Version => 6) ) + assert_raise(ArgumentError){ NetAddr.netmask_to_i({}) } + assert_raise(NetAddr::VersionError){ NetAddr.netmask_to_i('/24',:Version => 5) } + assert_raise(ArgumentError){ NetAddr.netmask_to_i([], :Version => 4) } + end + + def test_range + cidr4_1 = NetAddr::CIDR.create('192.168.1.0/24') + cidr4_2 = NetAddr::CIDR.create('192.168.1.50/24') + cidr4_3 = NetAddr::CIDR.create('192.168.1.2/24') + cidr6_1 = NetAddr::CIDR.create('fec0::/64') + cidr6_2 = NetAddr::CIDR.create('fec0::32/64') + + assert_raise(ArgumentError) {NetAddr.range(cidr4_1,cidr4_2, :test => true)} + assert_equal(['192.168.1.1'], NetAddr.range(cidr4_1,cidr4_2, :Limit => 1) ) + assert_equal(['fec0:0000:0000:0000:0000:0000:0000:0001'], NetAddr.range(cidr6_1,cidr6_2, :Limit => 1) ) + + list = NetAddr.range('192.168.1.0/24','192.168.1.50/24', :Bitstep => 2) + assert_equal(25, list.length) + assert_equal('192.168.1.49', list[24]) + + list = NetAddr.range(cidr4_1,cidr4_3, :Objectify => true) + assert_kind_of(NetAddr::CIDR, list[0]) + assert_equal('192.168.1.1/32', (list[0]).desc) + + assert_raise(ArgumentError){ NetAddr.range(:Limit => 1) } + assert_raise(NetAddr::VersionError){ NetAddr.range(cidr4_1,cidr6_2) } + + assert_equal(256, NetAddr.range('192.168.0.0', '192.168.0.255', :Size => true, :Inclusive => true) ) + end + + def test_shorten + assert_equal('fec0::', NetAddr.shorten('fec0:0000:0000:0000:0000:0000:0000:0000') ) + assert_equal('fec0::2:0:0:1', NetAddr.shorten('fec0:0000:0000:0000:0002:0000:0000:0001') ) + assert_equal('fec0::2:0:0:1', NetAddr.shorten('fec0:00:0000:0:02:0000:0:1') ) + assert_equal('fec0::2:2:0:0:1', NetAddr.shorten('fec0:0000:0000:0002:0002:0000:0000:0001') ) + assert_equal('fec0:0:0:1::', NetAddr.shorten('fec0:0000:0000:0001:0000:0000:0000:0000') ) + assert_equal('fec0:1:1:1:1:1:1:1', NetAddr.shorten('fec0:0001:0001:0001:0001:0001:0001:0001') ) + assert_equal('fec0:ffff:ffff:0:ffff:ffff:ffff:ffff', NetAddr.shorten('fec0:ffff:ffff:0000:ffff:ffff:ffff:ffff') ) + assert_equal('fec0:ffff:ffff:ffff:ffff:ffff:ffff:ffff', NetAddr.shorten('fec0:ffff:ffff:ffff:ffff:ffff:ffff:ffff') ) + assert_equal('fec0::', NetAddr.shorten('fec0::') ) + assert_equal('fec0::192.168.1.1', NetAddr.shorten('fec0:0:0:0:0:0:192.168.1.1') ) + assert_raise(ArgumentError){ NetAddr.shorten(1) } + end + + def test_sort + cidr4_1 = NetAddr::CIDR.create('192.168.1.0/24') + cidr4_2 = NetAddr::CIDR.create('192.168.1.128/25') + cidr4_3 = NetAddr::CIDR.create('192.168.1.64/26') + cidr4_4 = NetAddr::CIDR.create('192.168.1.0/30') + cidr4_5 = '192.168.2.0/24' + + cidr6_1 = NetAddr::CIDR.create('fec0::0/64') + cidr6_2 = NetAddr::CIDR.create('fec0::0/10') + cidr6_3 = NetAddr::CIDR.create('fe80::0/10') + cidr6_4 = 'fe80::0' + + sort1 = NetAddr.sort(['192.168.1.0/24','192.168.1.128/25','192.168.1.64/26','192.168.1.0/30','192.168.2.0/24']) + assert_equal(['192.168.1.0/24','192.168.1.0/30','192.168.1.64/26','192.168.1.128/25','192.168.2.0/24'], sort1) + sort1 = NetAddr.sort([cidr4_1,cidr4_2,cidr4_3,cidr4_4,cidr4_5]) + assert_equal([cidr4_1,cidr4_4,cidr4_3,cidr4_2,cidr4_5], sort1) + + sort2 = NetAddr.sort(['fec0::0/64','fec0::0/10','fe80::0/10','fe80::0']) + assert_equal(['fe80::0/10','fe80::0','fec0::0/10','fec0::0/64'], sort2) + sort2 = NetAddr.sort([cidr6_1,cidr6_2,cidr6_3,cidr6_4]) + assert_equal([cidr6_3,cidr6_4,cidr6_2,cidr6_1], sort2) + + sort3 = NetAddr.sort([cidr4_1,cidr4_2,cidr4_3,cidr4_4,cidr4_5], :Desc => true) + assert_equal([cidr4_5,cidr4_2,cidr4_3,cidr4_1,cidr4_4], sort3) + sort3 = NetAddr.sort(['192.168.1.0/24','192.168.1.128/25','192.168.1.64/26','192.168.1.0/30','192.168.2.0/24'], :Desc => true) + assert_equal(['192.168.2.0/24','192.168.1.128/25','192.168.1.64/26','192.168.1.0/24','192.168.1.0/30'], sort3) + + sort4 = NetAddr.sort(['192.168.1.0/24','192.168.1.128/25','192.168.1.64/26','192.168.1.0/30','192.168.2.0/24'], :ByMask => true) + assert_equal(['192.168.1.0/24','192.168.2.0/24','192.168.1.128/25','192.168.1.64/26','192.168.1.0/30'], sort4) + sort4 = NetAddr.sort([cidr4_1,cidr4_2,cidr4_3,cidr4_4,cidr4_5], :ByMask => true) + assert_equal([cidr4_1,cidr4_5,cidr4_2,cidr4_3,cidr4_4], sort4) + + sort5 = NetAddr.sort(['192.168.1.0/24','192.168.1.128/25','192.168.1.64/26','192.168.1.0/30','192.168.2.0/24'], :ByMask => true, :Desc => true) + assert_equal(['192.168.1.0/30','192.168.1.64/26','192.168.1.128/25','192.168.1.0/24','192.168.2.0/24'], sort5) + sort5 = NetAddr.sort([cidr4_1,cidr4_2,cidr4_3,cidr4_4,cidr4_5], :ByMask => true, :Desc => true) + assert_equal([cidr4_4,cidr4_3,cidr4_2,cidr4_1,cidr4_5], sort5) + end + + def test_supernets + assert_raise(ArgumentError){ NetAddr.supernets(1) } + assert_raise(ArgumentError){ NetAddr.supernets({}) } + + list4 = ['192.168.1.0', '192.168.1.1', '192.168.1.0/31', '10.1.1.0/24', '10.1.1.32/27'] + list6 = ['fec0::/64', 'fec0::', 'fe80::/32', 'fe80::1'] + assert_equal(['10.1.1.0/24','192.168.1.0/31'], NetAddr.supernets(list4) ) + assert_equal(['fe80:0000:0000:0000:0000:0000:0000:0000/32', 'fec0:0000:0000:0000:0000:0000:0000:0000/64'], NetAddr.supernets(list6) ) + assert_equal(['fe80::/32', 'fec0::/64'], NetAddr.supernets(list6, :Short => true) ) + + list4.push( NetAddr::CIDR.create('192.168.0.0/23') ) + list6.push( NetAddr::CIDR.create('fec0::/48') ) + summ = NetAddr.supernets(list4.concat(list6), :Objectify => true) + assert_equal('192.168.1.0/31', summ[0].tag[:Subnets][0].desc) + end + + def test_unshorten + assert_equal('fec0:0000:0000:0000:0000:0000:0000:0000', NetAddr.unshorten('fec0::') ) + assert_equal('fec0:0000:0000:0000:0002:0000:0000:0001', NetAddr.unshorten('fec0::2:0:0:1') ) + assert_equal('fec0:0000:0000:0000:0002:0000:0000:0001', NetAddr.unshorten('fec0:0:0:0:2:0:0:1') ) + assert_equal('0000:0000:0000:0000:0000:ffff:10.1.0.1', NetAddr.unshorten('::ffff:10.1.0.1') ) + + assert_raise(ArgumentError){ NetAddr.unshorten(1) } + end + + def test_validate_eui + assert_nothing_raised(NetAddr::ValidationError) {NetAddr.validate_eui('aa-bb-cc-dd-ee-ff')} + assert_nothing_raised(NetAddr::ValidationError) {NetAddr.validate_eui('aabb.ccdd.eeff') } + assert_nothing_raised(NetAddr::ValidationError) {NetAddr.validate_eui('aa:bb:cc:dd:ee:ff') } + assert_nothing_raised(NetAddr::ValidationError) {NetAddr.validate_eui('aabb.ccdd.eeff.1234') } + assert_raise(NetAddr::ValidationError){NetAddr.validate_eui('aabb.ccdd.eeff.123') } + assert_raise(NetAddr::ValidationError){NetAddr.validate_eui('aabb.ccdd.eeff.12312') } + assert_raise(NetAddr::ValidationError){NetAddr.validate_eui('aa-bb-c-dd-ee-ff') } + assert_raise(NetAddr::ValidationError){NetAddr.validate_eui('aa:bb:cc:dd:e:ff') } + assert_raise(NetAddr::ValidationError){NetAddr.validate_eui('aa:bb:cc:dd:ee:^^') } + assert_raise(NetAddr::ValidationError){NetAddr.validate_eui('aa:bb:cc:dd:ee:ZZ') } + assert_raise(ArgumentError){ NetAddr.validate_eui(0xaabbccddeeff) } + assert_raise(ArgumentError){ NetAddr.validate_eui() } + end + + def test_validate_ip_addr + assert_raise(ArgumentError) {NetAddr.validate_ip_addr('192.168.1.0', :test => true)} + assert_nothing_raised(Exception) {NetAddr.validate_ip_addr('192.168.1.0')} + assert_nothing_raised(Exception) {NetAddr.validate_ip_addr('255.255.255.255')} + assert_nothing_raised(Exception) {NetAddr.validate_ip_addr('224.0.0.1')} + assert_nothing_raised(Exception) {NetAddr.validate_ip_addr('0.192.0.1')} + assert_nothing_raised(Exception) {NetAddr.validate_ip_addr('0.0.0.0')} + assert_nothing_raised(Exception) {NetAddr.validate_ip_addr(0xff0000)} + assert_nothing_raised(Exception) {NetAddr.validate_ip_addr(2**32-1)} + assert_nothing_raised(Exception) {NetAddr.validate_ip_addr(0)} + + assert_nothing_raised(Exception) {NetAddr.validate_ip_addr('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff')} + assert_nothing_raised(Exception) {NetAddr.validate_ip_addr('::')} + assert_nothing_raised(Exception) {NetAddr.validate_ip_addr('ffff::1')} + assert_nothing_raised(Exception) {NetAddr.validate_ip_addr('1234:5678:9abc:def0:1234:5678:9abc:def0')} + assert_nothing_raised(Exception) {NetAddr.validate_ip_addr('::1')} + assert_nothing_raised(Exception) {NetAddr.validate_ip_addr('ffff::')} + assert_nothing_raised(Exception) {NetAddr.validate_ip_addr('0001::1')} + assert_nothing_raised(Exception) {NetAddr.validate_ip_addr('2001:4800::64.39.2.1')} + assert_nothing_raised(Exception) {NetAddr.validate_ip_addr('::1.1.1.1')} + assert_nothing_raised(Exception) {NetAddr.validate_ip_addr('::192.168.255.0')} + assert_nothing_raised(Exception) {NetAddr.validate_ip_addr(2**128-1)} + assert_nothing_raised(Exception) {NetAddr.validate_ip_addr('fec0:0:0:0:0:0:192.168.1.1')} + assert_nothing_raised(Exception) {NetAddr.validate_ip_addr('8080::8080:10.10.10.10')} + + assert_raise(NetAddr::ValidationError){ NetAddr.validate_ip_addr('') } + assert_raise(NetAddr::ValidationError){ NetAddr.validate_ip_addr('10.0') } + assert_raise(NetAddr::ValidationError){ NetAddr.validate_ip_addr('10.0..0') } + assert_raise(NetAddr::ValidationError){ NetAddr.validate_ip_addr('192.168.1.256') } + assert_raise(NetAddr::ValidationError){ NetAddr.validate_ip_addr('192..168.1.1') } + assert_raise(NetAddr::ValidationError){ NetAddr.validate_ip_addr('192.168.1a.255') } + assert_raise(NetAddr::ValidationError){ NetAddr.validate_ip_addr('192.168.1.1.1') } + assert_raise(NetAddr::ValidationError){ NetAddr.validate_ip_addr('ff.ff.ff.ff') } + assert_raise(NetAddr::ValidationError){ NetAddr.validate_ip_addr(2**128-1, :Version => 4) } + + assert_raise(NetAddr::ValidationError){ NetAddr.validate_ip_addr('ffff::1111::1111') } + assert_raise(NetAddr::ValidationError){ NetAddr.validate_ip_addr('abcd:efgh::1') } + assert_raise(NetAddr::ValidationError){ NetAddr.validate_ip_addr('fffff::1') } + assert_raise(NetAddr::ValidationError){ NetAddr.validate_ip_addr('fffg::1') } + assert_raise(NetAddr::ValidationError){ NetAddr.validate_ip_addr('ffff:::0::1') } + assert_raise(NetAddr::ValidationError){ NetAddr.validate_ip_addr('1:0:0:0:0:0:0:0:1') } + assert_raise(NetAddr::ValidationError){ NetAddr.validate_ip_addr('::192.168.256.0') } + assert_raise(NetAddr::ValidationError){ NetAddr.validate_ip_addr('::192.168.a3.0') } + assert_raise(NetAddr::ValidationError){ NetAddr.validate_ip_addr('::192.168.1.1.0') } + + assert_raise(ArgumentError){ NetAddr.validate_ip_addr({}) } + assert_raise(ArgumentError){ NetAddr.validate_ip_addr([])} + assert_raise(ArgumentError){ NetAddr.validate_ip_addr('192.168.1.0', :Version => 5)} + + end + + def test_validate_ip_netmask + assert_raise(ArgumentError) {NetAddr.validate_ip_netmask('255.255.255.255', :test => true)} + assert_nothing_raised(Exception) {NetAddr.validate_ip_netmask('255.255.255.255')} + assert_nothing_raised(Exception) {NetAddr.validate_ip_netmask('32')} + assert_nothing_raised(Exception) {NetAddr.validate_ip_netmask('/32')} + assert_nothing_raised(Exception) {NetAddr.validate_ip_netmask(32)} + assert_nothing_raised(Exception) {NetAddr.validate_ip_netmask(0xffffffff, :Integer => true)} + assert_nothing_raised(Exception) {NetAddr.validate_ip_netmask('128', :Version => 6)} + assert_nothing_raised(Exception) {NetAddr.validate_ip_netmask('/128', :Version => 6)} + assert_nothing_raised(Exception) {NetAddr.validate_ip_netmask(128, :Version => 6)} + + assert_raise(NetAddr::ValidationError){ NetAddr.validate_ip_netmask('255.192.255.0') } + assert_raise(NetAddr::ValidationError){ NetAddr.validate_ip_netmask(33) } + assert_raise(NetAddr::ValidationError){ NetAddr.validate_ip_netmask(129, :Version => 6) } + + assert_raise(ArgumentError){ NetAddr.validate_ip_netmask({}) } + assert_raise(ArgumentError){ NetAddr.validate_ip_netmask([])} + assert_raise(ArgumentError){ NetAddr.validate_ip_netmask('/24', :Version => 5)} + end + + def test_wildcard + cidr = NetAddr.wildcard('192.168.*') + assert_equal(NetAddr::CIDRv4, cidr.class ) + assert_equal(16, cidr.bits) + assert_equal('192.168.0.0', cidr.network) + + cidr = NetAddr.wildcard('192.*.1.0') + assert_equal(8, cidr.bits) + assert_equal('192.0.0.0', cidr.network) + + cidr = NetAddr.wildcard('fec0:*') + assert_equal(NetAddr::CIDRv6, cidr.class ) + assert_equal(16, cidr.bits) + assert_equal('fec0:0000:0000:0000:0000:0000:0000:0000', cidr.network) + + cidr = NetAddr.wildcard('fec0:1:*') + assert_equal(32, cidr.bits) + assert_equal('fec0:0001:0000:0000:0000:0000:0000:0000', cidr.network) + + assert_raise(ArgumentError){NetAddr.wildcard('fec0::*')} + assert_raise(ArgumentError){NetAddr.wildcard('::ffff:192.168.*')} + end + +end + + + + diff --git a/src/vendor/cache/netaddr-rb-c7a7de39b7e1/test/tree_test.rb b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/test/tree_test.rb new file mode 100644 index 00000000000..89848acc465 --- /dev/null +++ b/src/vendor/cache/netaddr-rb-c7a7de39b7e1/test/tree_test.rb @@ -0,0 +1,347 @@ +#!/usr/bin/ruby + +require_relative "../lib/netaddr.rb" +require 'test/unit' + + + +class TestTree < Test::Unit::TestCase + + def test_add + tree = NetAddr::Tree.new() + + assert_nothing_raised(RuntimeError){tree.add!('192.168.1.0 255.255.255.0')} + assert_nothing_raised(RuntimeError){tree.add!('10.1.0.0/24')} + assert_nothing_raised(RuntimeError){tree.add!('10.1.0.0')} + assert_nothing_raised(RuntimeError){tree.add!('192.168.1.0/26')} + assert_nothing_raised(RuntimeError){tree.add!('fec0::/10')} + assert_nothing_raised(RuntimeError){tree.add!('fec0::/64')} + + end + + def test_ancestors + tree = NetAddr::Tree.new() + + tree.add!('192.168.1.0/24') + tree.add!('192.168.1.64/26') + tree.add!('192.168.1.64/27') + tree.add!('192.168.1.64/28') + tree.add!('192.168.2.0/24') + + ancestors = tree.ancestors('192.168.1.64/28') + assert_equal('192.168.1.64/27', ancestors[0].desc) + assert_equal('192.168.1.64/26', ancestors[1].desc) + assert_equal('192.168.1.0/24', ancestors[2].desc) + + end + + def test_children + tree = NetAddr::Tree.new() + + tree.add!('192.168.1.0/24') + tree.add!('192.168.1.64/26') + tree.add!('192.168.1.64/27') + tree.add!('192.168.1.96/27') + tree.add!('192.168.1.64/28') + tree.add!('192.168.2.0/24') + + children = tree.children('192.168.1.64/26') + assert_equal('192.168.1.64/27', children[0].desc) + assert_equal('192.168.1.96/27', children[1].desc) + end + + def test_delete + tree = NetAddr::Tree.new() + + tree.add!('192.168.1.0/24') + tree.add!('192.168.1.64/26') + tree.add!('192.168.1.64/27') + tree.add!('192.168.1.64/28') + tree.add!('192.168.2.0/24') + + tree.delete!('192.168.1.64/27') + assert_equal('192.168.1.64/28', tree.children('192.168.1.64/26')[0].desc) + end + + def test_descendants + tree = NetAddr::Tree.new() + + tree.add!('192.168.1.0/24') + tree.add!('192.168.1.64/26') + tree.add!('192.168.1.64/27') + tree.add!('192.168.1.96/27') + tree.add!('192.168.1.64/28') + tree.add!('192.168.2.0/24') + + descendants = tree.descendants('192.168.1.64/26') + assert_equal('192.168.1.64/27', descendants[0].desc) + assert_equal('192.168.1.64/28', descendants[1].desc) + assert_equal('192.168.1.96/27', descendants[2].desc) + end + + def test_dump + tree = NetAddr::Tree.new() + + tree.add!('192.168.1.0/24') + tree.add!('10.1.0.0/24') + tree.add!('192.168.1.0/26') + tree.add!('192.168.1.0/30') + tree.add!('fec0::/10') + tree.add!('fe80::/10') + tree.add!('fec0::/64') + tree.add!('fec0::/126') + + dump = tree.dump() + + obj0 = dump[0][:CIDR] + obj1 = dump[1][:CIDR] + obj3 = dump[3][:CIDR] + assert_equal('10.1.0.0/24', obj0.desc) + assert_equal('192.168.1.0/24', obj1.desc) + assert_equal('192.168.1.0/30', obj3.desc) + + obj4 = dump[4][:CIDR] + obj5 = dump[5][:CIDR] + obj7 = dump[7][:CIDR] + assert_equal('fe80:0000:0000:0000:0000:0000:0000:0000/10', obj4.desc) + assert_equal('fec0:0000:0000:0000:0000:0000:0000:0000/10', obj5.desc) + assert_equal('fec0:0000:0000:0000:0000:0000:0000:0000/126', obj7.desc) + + end + + def test_exists + + tree = NetAddr::Tree.new() + + tree.add!('192.168.1.0/24') + tree.add!('10.1.0.0/24') + tree.add!('192.168.1.64/26') + tree.add!('10.1.0.44/30') + + assert_equal(true, tree.exists?('192.168.1.0/24')) + assert_equal(true, tree.exists?('10.1.0.44/30')) + assert_equal(false, tree.exists?('10.2.0.0/24')) + + end + + def test_fill_in + tree = NetAddr::Tree.new() + + tree.add!('192.168.1.0/24') + tree.add!('192.168.1.64/26') + + tree.fill_in!('192.168.1.0/24') + children = tree.children('192.168.1.0/24') + + assert_equal('192.168.1.0/26', children[0].desc) + assert_equal('192.168.1.64/26', children[1].desc) + assert_equal('192.168.1.128/25', children[2].desc) + end + + def test_find + tree = NetAddr::Tree.new() + + tree.add!('192.168.1.0/24') + tree.add!('10.1.0.0/24') + tree.add!('192.168.1.64/26') + tree.add!('10.1.0.44/30') + assert_equal('192.168.1.64/26', tree.longest_match('192.168.1.64/26').desc) + assert_equal('10.1.0.44/30', tree.longest_match('10.1.0.44/30').desc) + end + + def test_find_space + tree = NetAddr::Tree.new() + + cidr = ['192.168.1.0/24','192.168.1.0/26','192.168.1.64/26', + '192.168.1.128/26','192.168.1.192/26','192.168.1.0/27', + '192.168.1.0/28','192.168.1.16/30','192.168.1.16/29', + '192.168.1.32/27','192.168.1.24/30','192.168.1.28/30', + '192.168.1.64/27','192.168.1.25', + 'fec0::/60','fec0::/66','fec0::4000:0:0:0/66', + 'fec0::8000:0:0:0/66','fec0::c000:0:0:0/66','fec0::c000:0:0:0/67', + 'fec0::/67','fec0::2000:0:0:0/67','fec0::8000:0:0:0/67','fec0::4000:0:0:0/69'] + + assert_raise(ArgumentError) {tree.find_space(:test => true)} + cidr.each {|x| tree.add!(x)} + assert_equal(10, tree.find_space(:IPCount => 16).length) + end + + def test_longest_match + + tree = NetAddr::Tree.new() + + tree.add!('192.168.1.0/24') + tree.add!('10.1.0.0/24') + tree.add!('192.168.1.64/26') + tree.add!('10.1.0.44/30') + + assert_equal('192.168.1.64/26', tree.longest_match('192.168.1.65').desc) + assert_equal('10.1.0.44/30', tree.longest_match('10.1.0.46').desc) + assert_equal('0.0.0.0/0', tree.longest_match('192.168.2.0').desc ) + + end + + def test_merge_subnets + tree = NetAddr::Tree.new() + + tree.add!('192.168.1.0/24') + tree.add!('192.168.1.0/26') + tree.add!('192.168.1.64/26') + tree.add!('192.168.1.192/26') + + tree.merge_subnets!('192.168.1.0/24') + children = tree.children('192.168.1.0/24') + + assert_equal('192.168.1.0/25', children[0].desc) + assert_equal('192.168.1.192/26', children[1].desc) + end + + def test_prune + cidr4_1 = NetAddr::CIDR.create('192.168.1.0/24') + cidr4_2 = NetAddr::CIDR.create('10.1.0.0/24') + cidr4_3 = NetAddr::CIDR.create('192.168.1.0/26') + cidr4_4 = NetAddr::CIDR.create('192.168.1.0/30') + cidr4_5 = NetAddr::CIDR.create('192.168.1.64/26') + cidr4_6 = NetAddr::CIDR.create('192.168.1.128/26') + cidr4_7 = NetAddr::CIDR.create('192.168.1.192/26') + + tree4 = NetAddr::Tree.new() + + tree4.add!(cidr4_1) + tree4.add!(cidr4_2) + tree4.add!(cidr4_3) + tree4.add!(cidr4_4) + tree4.add!(cidr4_5) + tree4.add!(cidr4_6) + tree4.add!(cidr4_7) + + tree4.prune!(cidr4_5) + dump = tree4.dump + assert_equal(7, dump.length) + + tree4.prune!(cidr4_1) + dump = tree4.dump + assert_equal(2, dump.length) + end + + def test_remove + cidr4_1 = NetAddr::CIDR.create('192.168.1.0/24') + cidr4_2 = NetAddr::CIDR.create('10.1.0.0/24') + cidr4_3 = NetAddr::CIDR.create('192.168.1.0/26') + cidr4_4 = NetAddr::CIDR.create('192.168.1.0/30') + cidr4_5 = NetAddr::CIDR.create('192.168.1.64/26') + cidr4_6 = NetAddr::CIDR.create('192.168.1.128/26') + cidr4_7 = NetAddr::CIDR.create('192.168.1.192/26') + + tree4 = NetAddr::Tree.new() + + tree4.add!(cidr4_1) + tree4.add!(cidr4_2) + tree4.add!(cidr4_3) + tree4.add!(cidr4_4) + tree4.add!(cidr4_5) + tree4.add!(cidr4_6) + tree4.add!(cidr4_7) + + tree4.remove!(cidr4_5) + dump = tree4.dump + assert_equal(6, dump.length) + + tree4.remove!(cidr4_1) + dump = tree4.dump + assert_equal(1, dump.length) + end + + def test_root + tree = NetAddr::Tree.new() + + tree.add!('192.168.1.0/24') + tree.add!('192.168.1.64/26') + tree.add!('192.168.1.64/27') + tree.add!('192.168.2.0/24') + + assert_equal('192.168.1.0/24', tree.root('192.168.1.64/27').desc) + end + + def test_show + cidr4_1 = NetAddr::CIDR.create('192.168.1.0/24') + cidr4_2 = NetAddr::CIDR.create('10.1.0.0/24') + cidr4_3 = NetAddr::CIDR.create('192.168.1.0/26') + cidr4_4 =NetAddr::CIDR.create('192.168.1.0/30') + cidr4_5 = NetAddr::CIDR.create('192.168.1.64/26') + cidr4_6 = NetAddr::CIDR.create('192.168.1.128/26') + cidr4_7 = NetAddr::CIDR.create('192.168.1.192/26') + + tree4 = NetAddr::Tree.new() + + tree4.add!(cidr4_1) + tree4.add!(cidr4_2) + tree4.add!(cidr4_3) + tree4.add!(cidr4_4) + tree4.add!(cidr4_5) + tree4.add!(cidr4_6) + tree4.add!(cidr4_7) + + assert_not_nil(tree4.show()) + end + + def test_siblings + tree = NetAddr::Tree.new() + + tree.add!('192.168.1.0/24') + tree.add!('192.168.1.0/26') + tree.add!('192.168.1.64/26') + tree.add!('192.168.1.128/26') + tree.add!('192.168.1.192/26') + + assert_equal(3, tree.siblings('192.168.1.0/26').length) + end + + def test_interactions + show1 = "IPv4 Tree\n---------\n192.168.12.0/26\n 192.168.12.8/29\n 192.168.12.8/30\n" + show2 = "IPv4 Tree\n---------\n192.168.12.0/26\n 192.168.12.8/29\n 192.168.12.8/30\n 192.168.12.12/30\n" + show3 = "IPv4 Tree\n---------\n192.168.12.0/26\n 192.168.12.0/29\n 192.168.12.8/29\n 192.168.12.8/30\n" + + " 192.168.12.12/30\n 192.168.12.16/28\n 192.168.12.32/27\n" + show4 = "IPv4 Tree\n---------\n192.168.12.0/26\n 192.168.12.0/29\n 192.168.12.8/30\n 192.168.12.12/30\n" + + " 192.168.12.16/28\n 192.168.12.32/27\n" + show5 = "IPv4 Tree\n---------\n192.168.12.0/26\n 192.168.12.0/28\n 192.168.12.0/29\n" + + " 192.168.12.8/29\n 192.168.12.8/30\n 192.168.12.12/30\n 192.168.12.16/28\n 192.168.12.32/27\n" + show6 = "IPv4 Tree\n---------\n192.168.12.0/26\n 192.168.12.0/28\n 192.168.12.0/29\n" + + " 192.168.12.8/29\n 192.168.12.16/28\n 192.168.12.32/27\n" + show7 = "IPv4 Tree\n---------\n192.168.12.0/26\n 192.168.12.16/28\n 192.168.12.32/27\n" + show8 = "IPv4 Tree\n---------\n192.168.12.0/24\n 192.168.12.16/28\n 192.168.12.32/27\n 192.168.12.64/26\n" + show9 = "IPv4 Tree\n---------\n192.168.12.0/24\n 192.168.12.0/25\n 192.168.12.0/26\n" + + " 192.168.12.16/28\n 192.168.12.32/27\n 192.168.12.64/26\n" + + tree = NetAddr::Tree.new + tree.add!('192.168.12.0/26') + tree.add!('192.168.12.8/29') + tree.add!('192.168.12.8/30') + assert_equal(show1, tree.show) + tree.fill_in! '192.168.12.8/29' + assert_equal(show2, tree.show) + tree.fill_in! '192.168.12.0/26' + assert_equal(show3, tree.show) + tree.delete!('192.168.12.8/29') + assert_equal(show4, tree.show) + tree.add!('192.168.12.8/29') + tree.add!('192.168.12.0/28') + tree.add!('192.168.12.0/29') + assert_equal(show5, tree.show) + tree.prune!('192.168.12.8/29') + assert_equal(show6, tree.show) + tree.remove!('192.168.12.0/28') + assert_equal(show7, tree.show) + tree.add!('192.168.12.64/26') + tree.resize!('192.168.12.0/26', 24) + assert_equal(show8, tree.show) + tree.add!('192.168.12.0/26') + tree.summarize_subnets!('192.168.12.0/24') + assert_equal(show9, tree.show) + end + +end + + + +