lib/ipaddress/ipv6.rb in ipaddress-0.7.5 vs lib/ipaddress/ipv6.rb in ipaddress-0.8.0
- old
+ new
@@ -20,11 +20,11 @@
# which are only 32 bits long. An IPv6 address is generally written as
# eight groups of four hexadecimal digits, each group representing 16
# bits or two octect. For example, the following is a valid IPv6
# address:
#
- # 1080:0000:0000:0000:0008:0800:200c:417a
+ # 2001:0db8:0000:0000:0008:0800:200c:417a
#
# Letters in an IPv6 address are usually written downcase, as per
# RFC. You can create a new IPv6 object using uppercase letters, but
# they will be converted.
#
@@ -40,20 +40,20 @@
# "::". This can be only applied once.
#
# Using compression, the IPv6 address written above can be shorten into
# the following, equivalent, address
#
- # 1080::8:800:200c:417a
+ # 2001:db8::8:800:200c:417a
#
# This short version is often used in human representation.
#
# === Network Mask
#
# As we used to do with IPv4 addresses, an IPv6 address can be written
# using the prefix notation to specify the subnet mask:
#
- # 1080::8:800:200c:417a/64
+ # 2001:db8::8:800:200c:417a/64
#
# The /64 part means that the first 64 bits of the address are
# representing the network portion, and the last 64 bits are the host
# portion.
#
@@ -73,13 +73,13 @@
#
# Creates a new IPv6 address object.
#
# An IPv6 address can be expressed in any of the following forms:
#
- # * "1080:0000:0000:0000:0008:0800:200C:417A": IPv6 address with no compression
- # * "1080:0:0:0:8:800:200C:417A": IPv6 address with leading zeros compression
- # * "1080::8:800:200C:417A": IPv6 address with full compression
+ # * "2001:0db8:0000:0000:0008:0800:200C:417A": IPv6 address with no compression
+ # * "2001:db8:0:0:8:800:200C:417A": IPv6 address with leading zeros compression
+ # * "2001:db8::8:800:200C:417A": IPv6 address with full compression
#
# In all these 3 cases, a new IPv6 address object will be created, using the default
# subnet mask /128
#
# You can also specify the subnet mask as with IPv4 addresses:
@@ -327,10 +327,40 @@
def network_u128
to_u128 & @prefix.to_u128
end
#
+ # Returns the broadcast address in Unsigned 128bits format
+ #
+ # ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
+ #
+ # ip6.broadcast_u128
+ # #=> 42540766411282592875350729025363378175
+ #
+ # Please note that there is no Broadcast concept in IPv6
+ # addresses as in IPv4 addresses, and this method is just
+ # an helper to other functions.
+ #
+ def broadcast_u128
+ network_u128 + size - 1
+ end
+
+ #
+ # Returns the number of IP addresses included
+ # in the network. It also counts the network
+ # address and the broadcast address.
+ #
+ # ip6 = IPAddress("2001:db8::8:800:200c:417a/64")
+ #
+ # ip6.size
+ # #=> 18446744073709551616
+ #
+ def size
+ 2 ** @prefix.host_prefix
+ end
+
+ #
# Checks whether a subnet includes the given IP address.
#
# Example:
#
# ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
@@ -382,12 +412,79 @@
# See IPAddress::IPv6::Mapped for more information
#
def mapped?
to_u128 >> 32 == 0xffff
end
-
+
#
+ # Iterates over all the IP addresses for the given
+ # network (or IP address).
+ #
+ # The object yielded is a new IPv6 object created
+ # from the iteration.
+ #
+ # ip6 = IPAddress("2001:db8::4/125")
+ #
+ # ip6.each do |i|
+ # p i.compressed
+ # end
+ # #=> "2001:db8::"
+ # #=> "2001:db8::1"
+ # #=> "2001:db8::2"
+ # #=> "2001:db8::3"
+ # #=> "2001:db8::4"
+ # #=> "2001:db8::5"
+ # #=> "2001:db8::6"
+ # #=> "2001:db8::7"
+ #
+ # WARNING: if the host portion is very large, this method
+ # can be very slow and possibly hang your system!
+ #
+ def each
+ (network_u128..broadcast_u128).each do |i|
+ yield self.class.parse_u128(i, @prefix)
+ end
+ end
+
+ #
+ # Spaceship operator to compare IPv6 objects
+ #
+ # Comparing IPv6 addresses is useful to ordinate
+ # them into lists that match our intuitive
+ # perception of ordered IP addresses.
+ #
+ # The first comparison criteria is the u128 value.
+ # For example, 2001:db8:1::1 will be considered
+ # to be less than 2001:db8:2::1, because, in a ordered list,
+ # we expect 2001:db8:1::1 to come before 2001:db8:2::1.
+ #
+ # The second criteria, in case two IPv6 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
+ # 2001:db8:1::1/64 come before 2001:db8:1::1/65
+ #
+ # Example:
+ #
+ # ip1 = IPAddress "2001:db8:1::1/64"
+ # ip2 = IPAddress "2001:db8:2::1/64"
+ # ip3 = IPAddress "2001:db8:1::1/65"
+ #
+ # ip1 < ip2
+ # #=> true
+ # ip1 < ip3
+ # #=> false
+ #
+ # [ip1,ip2,ip3].sort.map{|i| i.to_string}
+ # #=> ["2001:db8:1::1/64","2001:db8:1::1/65","2001:db8:2::1/64"]
+ #
+ def <=>(oth)
+ return prefix <=> oth.prefix if to_u128 == oth.to_u128
+ to_u128 <=> oth.to_u128
+ end
+
+ #
# Returns the address portion of an IP in binary format,
# as a string containing a sequence of 0 and 1
#
# ip6 = IPAddress("2001:db8::8:800:200c:417a")
#
@@ -429,10 +526,23 @@
def literal
@address.gsub(":","-") + ".ipv6-literal.net"
end
#
+ # Returns a new IPv6 object with the network number
+ # for the given IP.
+ #
+ # ip = IPAddress "2001:db8:1:1:1:1:1:1/32"
+ #
+ # ip.network.to_string
+ # #=> "2001:db8::/32"
+ #
+ def network
+ self.class.parse_u128(network_u128, @prefix)
+ end
+
+ #
# Extract 16 bits groups from a string
#
def self.groups(str)
l, r = if str =~ /^(.*)::(.*)$/
[$1,$2].map {|i| i.split ":"}
@@ -468,22 +578,22 @@
#
# Creates a new IPv6 object from an
# unsigned 128 bits integer.
#
- # ip6 = IPAddress::IPv6::parse_u128(21932261930451111902915077091070067066)
+ # ip6 = IPAddress::IPv6::parse_u128(42540766411282592856906245548098208122)
# ip6.prefix = 64
#
- # ip6.to_s
- # #=> "1080::8:800:200c:417a/64"
+ # ip6.to_string
+ # #=> "2001:db8::8:800:200c:417a/64"
#
# The +prefix+ parameter is optional:
#
- # ip6 = IPAddress::IPv6::parse_u128(21932261930451111902915077091070067066, 64)
+ # ip6 = IPAddress::IPv6::parse_u128(42540766411282592856906245548098208122, 64)
#
- # ip6.to_s
- # #=> "1080::8:800:200c:417a/64"
+ # ip6.to_string
+ # #=> "2001:db8::8:800:200c:417a/64"
#
def self.parse_u128(u128, prefix=128)
str = IN6FORMAT % (0..7).map{|i| (u128>>(112-16*i))&0xffff}
self.new(str + "/#{prefix}")
end
@@ -493,19 +603,19 @@
# hexdecimal format:
#
# ip6 = IPAddress::IPv6::parse_hex("20010db80000000000080800200c417a")
# ip6.prefix = 64
#
- # ip6.to_s
+ # ip6.to_string
# #=> "2001:db8::8:800:200c:417a/64"
#
# The +prefix+ parameter is optional:
#
# ip6 = IPAddress::IPv6::parse_hex("20010db80000000000080800200c417a", 64)
#
- # ip6.to_s
- # #=> "1080::8:800:200c:417a/64"
+ # ip6.to_string
+ # #=> "2001:db8::8:800:200c:417a/64"
#
def self.parse_hex(hex, prefix=128)
self.parse_u128(hex.hex, prefix)
end
@@ -603,18 +713,18 @@
# As for the unspecified addresses, IPv6 loopbacks can be created with
# IPAddress calling their own class:
#
# ip = IPAddress::IPv6::Loopback.new
#
- # ip.to_s
+ # ip.to_string
# #=> "::1/128"
#
# or by using the wrapper:
#
# ip = IPAddress "::1"
#
- # ip.to_s
+ # ip.to_string
# #=> "::1/128"
#
# Checking if an address is loopback is easy with the IPv6#loopback?
# method:
#
@@ -627,11 +737,11 @@
#
# Creates a new IPv6 unspecified address
#
# ip = IPAddress::IPv6::Loopback.new
#
- # ip.to_s
+ # ip.to_string
# #=> "::1/128"
#
def initialize
@address = ("0000:"*7)+"0001"
@groups = Array.new(7,0).push(1)
@@ -666,11 +776,11 @@
# Let's check it's really a mapped address:
#
# ip6.mapped?
# #=> true
#
- # ip6.to_s
+ # ip6.to_string
# #=> "::FFFF:172.16.10.1/128"
#
# Now with the +ipv4+ attribute, we can easily access the IPv4 portion
# of the mapped IPv6 address:
#
@@ -693,11 +803,11 @@
# ip6 = IPAddress "::172.16.10.1"
#
# That is, two colons and the IPv4 address. However, as by RFC, the ffff
# group will be automatically added at the beginning
#
- # ip6.to_s
+ # ip6.to_string
# => "::ffff:172.16.10.1/128"
#
# making it a mapped IPv6 compatible address.
#
class IPAddress::IPv6::Mapped < IPAddress::IPv6
@@ -716,10 +826,10 @@
# An IPv6 IPv4-mapped address can also be created using the
# IPv6 only format of the address:
#
# ip6 = IPAddress::IPv6::Mapped.new "::0d01:4403"
#
- # ip6.to_s
+ # ip6.to_string
# #=> "::ffff:13.1.68.3"
#
def initialize(str)
string, netmask = str.split("/")
if string =~ /\./ # IPv4 in dotted decimal form