diff --git a/packages/director/packaging b/packages/director/packaging index bbcbfa03992..32412a211ba 100644 --- a/packages/director/packaging +++ b/packages/director/packaging @@ -22,6 +22,11 @@ pushd vendor/cache/eventmachine-* > /dev/null mv *.gem ../ popd > /dev/null +pushd vendor/cache/netaddr-rb-* > /dev/null + gem build netaddr.gemspec + mv *.gem ../ +popd > /dev/null + cat > Gemfile <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 c7d3e4dec13..00000000000 Binary files a/src/vendor/cache/netaddr-1.5.1.gem and /dev/null differ 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 + + + +