lib/ipaddress/ipv4.rb in ipaddress-0.7.5 vs lib/ipaddress/ipv4.rb in ipaddress-0.8.0
- old
+ new
@@ -424,43 +424,44 @@
yield self.class.parse_u32(i, @prefix)
end
end
#
- # Spaceship operator to compare IP addresses
+ # Spaceship operator to compare IPv4 objects
#
- # An IP address is considered to be minor if it
- # has a greater prefix (thus smaller hosts
- # portion) and a smaller u32 value.
+ # Comparing IPv4 addresses is useful to ordinate
+ # them into lists that match our intuitive
+ # perception of ordered IP addresses.
+ #
+ # The first comparison criteria is the u32 value.
+ # For example, 10.100.100.1 will be considered
+ # to be less than 172.16.0.1, because, in a ordered list,
+ # we expect 10.100.100.1 to come before 172.16.0.1.
#
- # For example, "10.100.100.1/8" is smaller than
- # "172.16.0.1/16", but it's bigger than "10.100.100.1/16".
+ # The second criteria, in case two IPv4 objects
+ # have identical addresses, is the prefix. An higher
+ # prefix will be considered greater than a lower
+ # prefix. This is because we expect to see
+ # 10.100.100.0/24 come before 10.100.100.0/25.
#
# Example:
#
# ip1 = IPAddress "10.100.100.1/8"
# ip2 = IPAddress "172.16.0.1/16"
# ip3 = IPAddress "10.100.100.1/16"
#
# ip1 < ip2
# #=> true
- # ip1 < ip3
+ # ip1 > ip3
# #=> false
#
+ # [ip1,ip2,ip3].sort.map{|i| i.to_string}
+ # #=> ["10.100.100.1/8","10.100.100.1/16","172.16.0.1/16"]
+ #
def <=>(oth)
- if to_u32 > oth.to_u32
- return 1
- elsif to_u32 < oth.to_u32
- return -1
- else
- if prefix < oth.prefix
- return 1
- elsif prefix > oth.prefix
- return -1
- end
- end
- return 0
+ return prefix <=> oth.prefix if to_u32 == oth.to_u32
+ to_u32 <=> oth.to_u32
end
#
# Returns the number of IP addresses included
# in the network. It also counts the network
@@ -551,34 +552,10 @@
def include_all?(*others)
others.all? {|oth| include?(oth)}
end
#
- # True if the object is an IPv4 address
- #
- # ip = IPAddress("192.168.10.100/24")
- #
- # ip.ipv4?
- # #-> true
- #
-# def ipv4?
-# true
-# end
-
- #
- # True if the object is an IPv6 address
- #
- # ip = IPAddress("192.168.10.100/24")
- #
- # ip.ipv6?
- # #-> false
- #
-# def ipv6?
-# false
-# end
-
- #
# Checks if an IPv4 address objects belongs
# to a private network RFC1918
#
# Example:
#
@@ -605,14 +582,14 @@
@octets.reverse.join(".") + ".in-addr.arpa"
end
alias_method :arpa, :reverse
#
- # Subnetting a network
+ # Splits a network into different subnets
#
# If the IP Address is a network, it can be divided into
- # multiple networks. If +self+ is not a network, the
+ # multiple networks. If +self+ is not a network, this
# method will calculate the network from the IP and then
# subnet it.
#
# If +subnets+ is an power of two number, the resulting
# networks will be divided evenly from the supernet.
@@ -634,19 +611,23 @@
# network / 3 # implies map{|i| i.to_string}
# #=> ["172.16.10.0/26",
# "172.16.10.64/26",
# "172.16.10.128/25"]
#
- # Returns an array of IPAddress objects
+ # Returns an array of IPv4 objects
#
- def subnet(subnets=2)
+ def split(subnets=2)
unless (1..(2**@prefix.host_prefix)).include? subnets
raise ArgumentError, "Value #{subnets} out of range"
end
- calculate_subnets(subnets)
+ networks = subnet(newprefix(subnets))
+ until networks.size == subnets
+ networks = sum_first_found(networks)
+ end
+ return networks
end
- alias_method :/, :subnet
+ alias_method :/, :split
#
# Returns a new IPv4 object from the supernetting
# of the instance network.
#
@@ -665,18 +646,51 @@
# However if you supernet it with a /22 prefix, the
# network address will change:
#
# ip.supernet(22).to_string
# #=> "172.16.8.0/22"
- #
+ #
+ # If +new_prefix+ is less than 1, returns 0.0.0.0/0
+ #
def supernet(new_prefix)
- raise ArgumentError, "Can't supernet a /1 network" if new_prefix < 1
raise ArgumentError, "New prefix must be smaller than existing prefix" if new_prefix >= @prefix.to_i
- self.class.new(@address+"/#{new_prefix}").network
+ return self.class.new("0.0.0.0/0") if new_prefix < 1
+ return self.class.new(@address+"/#{new_prefix}").network
end
#
+ # This method implements the subnetting function
+ # similar to the one described in RFC3531.
+ #
+ # By specifying a new prefix, the method calculates
+ # the network number for the given IPv4 object
+ # and calculates the subnets associated to the new
+ # prefix.
+ #
+ # For example, given the following network:
+ #
+ # ip = IPAddress "172.16.10.0/24"
+ #
+ # we can calculate the subnets with a /26 prefix
+ #
+ # ip.subnets(26).map{&:to_string)
+ # #=> ["172.16.10.0/26", "172.16.10.64/26",
+ # "172.16.10.128/26", "172.16.10.192/26"]
+ #
+ # The resulting number of subnets will of course always be
+ # a power of two.
+ #
+ def subnet(subprefix)
+ unless ((@prefix.to_i)..32).include? subprefix
+ raise ArgumentError, "New prefix must be between #@prefix and 32"
+ end
+ Array.new(2**(subprefix-@prefix.to_i)) do |i|
+ self.class.parse_u32(network_u32+(i*(2**(32-subprefix))), subprefix)
+ end
+ end
+
+ #
# Returns the difference between two IP addresses
# in unsigned int 32 bits format
#
# Example:
#
@@ -926,22 +940,22 @@
#
# * Class A, from 0.0.0.0 to 127.255.255.255
# * Class B, from 128.0.0.0 to 191.255.255.255
# * Class C, D and E, from 192.0.0.0 to 255.255.255.254
#
- # Note that classes C, D and E will all have a default
- # prefix of /24 or 255.255.255.0
- #
# Example:
#
# ip = IPAddress::IPv4.parse_classful "10.0.0.1"
#
# ip.netmask
# #=> "255.0.0.0"
# ip.a?
# #=> true
#
+ # Note that classes C, D and E will all have a default
+ # prefix of /24 or 255.255.255.0
+ #
def self.parse_classful(ip)
if IPAddress.valid_ipv4?(ip)
address = ip.strip
else
raise ArgumentError, "Invalid IP #{ip.inspect}"
@@ -952,28 +966,22 @@
#
# private methods
#
private
-
- def calculate_subnets(subnets)
- po2 = subnets.closest_power_of_2
- new_prefix = @prefix + Math::log2(po2).to_i
- networks = Array.new
- (0..po2-1).each do |i|
- mul = i * (2**(32-new_prefix))
- networks << IPAddress::IPv4.parse_u32(network_u32+mul, new_prefix)
+
+ def newprefix(num)
+ num.upto(32) do |i|
+ if (a = Math::log2(i).to_i) == Math::log2(i)
+ return @prefix + a
+ end
end
- until networks.size == subnets
- networks = sum_first_found(networks)
- end
- return networks
end
def sum_first_found(arr)
dup = arr.dup.reverse
dup.each_with_index do |obj,i|
- a = [IPAddress::IPv4.summarize(obj,dup[i+1])].flatten
+ a = [self.class.summarize(obj,dup[i+1])].flatten
if a.size == 1
dup[i..i+1] = a
return dup.reverse
end
end