class IPAddress::IPv6
Name¶ ↑
IPAddress::IPv6
- IP version 6 address manipulation library
Synopsis¶ ↑
require 'ipaddress'
Description¶ ↑
Class IPAddress::IPv6
is used to handle IPv6
type addresses.
IPv6
addresses¶ ↑
IPv6
addresses are 128 bits long, in contrast with IPv4
addresses 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:
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.
Compression¶ ↑
Since IPv6
addresses are very long to write, there are some semplifications and compressions that you can use to shorten them.
-
Leading zeroes: all the leading zeroes within a group can be omitted: “0008” would become “8”
-
A string of consecutive zeroes can be replaced by the string “::”. This can be only applied once.
Using compression, the IPv6
address written above can be shorten into the following, equivalent, address
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:
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.
Constants
- IN6FORMAT
Format string to pretty print
IPv6
addresses
Public Class Methods
Compress an IPv6
address in its compressed form
IPAddress::IPv6.compress "2001:0DB8:0000:CD30:0000:0000:0000:0000" #=> "2001:db8:0:cd30::"
# File lib/ipaddress_2/ipv6.rb, line 925 def self.compress(str) self.new(str).compressed end
Expands an IPv6
address in the canocical form
IPAddress::IPv6.expand "2001:0DB8:0:CD30::" #=> "2001:0DB8:0000:CD30:0000:0000:0000:0000"
# File lib/ipaddress_2/ipv6.rb, line 915 def self.expand(str) self.new(str).address end
Extract 16 bits groups from a string
# File lib/ipaddress_2/ipv6.rb, line 974 def self.groups(str) l, r = if str =~ /^(.*)::(.*)$/ [$1,$2].map {|i| i.split ":"} else [str.split(":"),[]] end (l + Array.new(8-l.size-r.size, '0') + r).map {|i| i.hex} end
Creates a new IPv6
address object.
An IPv6
address can be expressed in any of the following forms:
-
“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:
ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
# File lib/ipaddress_2/ipv6.rb, line 89 def initialize(str) raise ArgumentError, "Nil IP" unless str ip, netmask = str.split("/") if str =~ /:.+\./ raise ArgumentError, "Please use #{self.class}::Mapped for IPv4 mapped addresses" end if IPAddress.valid_ipv6?(ip) @groups = self.class.groups(ip) @address = IN6FORMAT % @groups @compressed = compress_address else raise ArgumentError, "Invalid IP #{ip.inspect}" end @prefix = Prefix128.new(netmask ? netmask : 128) @allocator = 0 end
Creates a new IPv6
object from binary data, like the one you get from a network stream.
For example, on a network stream the IP
"2001:db8::8:800:200c:417a"
is represented with the binary data
" \001\r\270\000\000\000\000\000\b\b\000 \fAz"
With that data you can create a new IPv6
object:
ip6 = IPAddress::IPv6::parse_data " \001\r\270\000\000\000\000\000\b\b\000 \fAz" ip6.prefix = 64 ip6.to_s #=> "2001:db8::8:800:200c:417a/64"
# File lib/ipaddress_2/ipv6.rb, line 1003 def self.parse_data(str) self.new(IN6FORMAT % str.unpack("n8")) end
Creates a new IPv6
object from a number expressed in hexdecimal format:
ip6 = IPAddress::IPv6::parse_hex("20010db80000000000080800200c417a") ip6.prefix = 64 ip6.to_string #=> "2001:db8::8:800:200c:417a/64"
The prefix
parameter is optional:
ip6 = IPAddress::IPv6::parse_hex("20010db80000000000080800200c417a", 64) ip6.to_string #=> "2001:db8::8:800:200c:417a/64"
# File lib/ipaddress_2/ipv6.rb, line 1046 def self.parse_hex(hex, prefix=128) self.parse_u128(hex.hex, prefix) end
Creates a new IPv6
object from an unsigned 128 bits integer.
ip6 = IPAddress::IPv6::parse_u128(42540766411282592856906245548098208122) ip6.prefix = 64 ip6.to_string #=> "2001:db8::8:800:200c:417a/64"
The prefix
parameter is optional:
ip6 = IPAddress::IPv6::parse_u128(42540766411282592856906245548098208122, 64) ip6.to_string #=> "2001:db8::8:800:200c:417a/64"
# File lib/ipaddress_2/ipv6.rb, line 1024 def self.parse_u128(u128, prefix=128) str = IN6FORMAT % (0..7).map{|i| (u128>>(112-16*i))&0xffff} self.new(str + "/#{prefix}") end
Summarization (or aggregation) is the process when two or more networks are taken together to check if a supernet, including all and only these networks, exists. If it exists then this supernet is called the summarized (or aggregated) network.
It is very important to understand that summarization can only occur if there are no holes in the aggregated network, or, in other words, if the given networks fill completely the address space of the supernet. So the two rules are:
1) The aggregate network must contain all
the IP addresses of the
original networks;
2) The aggregate network must contain only
the IP addresses of the
original networks;
A few examples will help clarify the above. Let's consider for instance the following two networks:
ip1 = IPAddress("2001:db8:8:800::1/64") ip2 = IPAddress("2001:0db8:8:801::2/64")
These two networks can be expressed using only one IP address network if we change the prefix. Let Ruby do the work:
IPAddress::IPv6::summarize(ip1,ip2).to_s #=> "2001:db8:8:800::/63"
We note how the network “2001:db8:8:800::/63” includes all the addresses specified in the above networks, and (more important) includes ONLY those addresses.
If we summarized ip1
and ip2
with the following network:
"2001:db8::/32"
we would have satisfied rule #1 above, but not rule #2. So “2001:db8::/32” is not an aggregate network for ip1
and ip2
.
If it's not possible to compute a single aggregated network for all the original networks, the method returns an array with all the aggregate networks found. For example, the following four networks can be aggregated in a single /22:
ip1 = IPAddress("2001:db8:8:800::1/64") ip2 = IPAddress("2001:db8:8:801::1/64") ip3 = IPAddress("2001:db8:8:802::1/64") ip4 = IPAddress("2001:db8:8:803::1/64") IPAddress::IPv6::summarize(ip1,ip2,ip3,ip4).to_string #=> "2001:db8:8:800::/62",
But the following networks can't be summarized in a single network:
ip1 = IPAddress("2001:db8:8:801::1/64") ip2 = IPAddress("2001:db8:8:802::1/64") ip3 = IPAddress("2001:db8:8:803::1/64") ip4 = IPAddress("2001:db8:8:804::1/64") IPAddress::IPv6::summarize(ip1,ip2,ip3,ip4).map{|i| i.to_string} #=> ["2001:db8:8:801::/64","2001:db8:8:802::/63","2001:db8:8:804::/64"]
# File lib/ipaddress_2/ipv6.rb, line 1112 def self.summarize(*args) # one network? no need to summarize return [args.first.network] if args.size == 1 args_size = args.size i = 0 result = args.sort.map{|ip| ip.network} while i < result.size-1 sum = result[i] + result[i+1] result[i..i+1] = sum.first if sum.size == 1 i += 1 end result.flatten! if result.size == args_size # nothing more to summarize return result else # keep on summarizing return self.summarize(*result) end end
Public Instance Methods
Returns a new IPv6
object which is the result of the summarization, if possible, of the two objects
Example:
ip1 = IPAddress("172.16.10.1/24") ip2 = IPAddress("172.16.11.2/24") p (ip1 + ip2).map {|i| i.to_string} #=> ["172.16.10.0/23"]
If the networks are not contiguous, returns the two network numbers from the objects
ip1 = IPAddress("10.0.0.1/24") ip2 = IPAddress("10.0.2.1/24") p (ip1 + ip2).map {|i| i.to_string} #=> ["10.0.0.0/24","10.0.2.0/24"]
# File lib/ipaddress_2/ipv6.rb, line 733 def +(oth) aggregate(*[self,oth].sort.map{|i| i.network}) 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"]
# File lib/ipaddress_2/ipv6.rb, line 890 def <=>(oth) return nil unless oth.is_a?(self.class) return prefix <=> oth.prefix if to_u128 == oth.to_u128 to_u128 <=> oth.to_u128 end
Returns the 16-bits value specified by index
ip = IPAddress("2001:db8::8:800:200c:417a/64") ip[0] #=> 8193 ip[1] #=> 3512 ip[2] #=> 0 ip[3] #=> 0
# File lib/ipaddress_2/ipv6.rb, line 320 def [](index) @groups[index] end
Updated the octet specified at index
# File lib/ipaddress_2/ipv6.rb, line 328 def []=(index, value) @groups[index] = value initialize("#{IN6FORMAT % @groups}/#{prefix}") end
Returns a new IPv6
object which is the result of advancing this IP address by a given value. In other words, this arithmetically adds IP addresses.
Will raise an error if the resulting address is in a different subnet, except validating is set to false.
Example:
ip = IPAddress::IPv6.new("fc42:1337::/64") ip.add(5).to_string #=> "fc42:1337::5/64"
# File lib/ipaddress_2/ipv6.rb, line 411 def add(oth, validating=true) oth = oth.to_i if oth.kind_of? IPAddress::IPv6 # oth shall be integer new_obj = self.class.parse_u128(self.to_i + oth, prefix) if validating and self.network_u128 != new_obj.network_u128 raise RuntimeError, "Subnet (/#{@prefix}) is not large enough." end new_obj end
Returns the IPv6
address in uncompressed form:
ip6 = IPAddress "2001:db8::8:800:200c:417a/64" ip6.address #=> "2001:0db8:0000:0000:0008:0800:200c:417a"
# File lib/ipaddress_2/ipv6.rb, line 118 def address @address end
Returns the network address of the n-th network succeeding this one.
Example:
ip = IPAddress::IPv6.new("fc42:1337:0:0::/64") ip.advance_network(5).to_string #=> "fc42:1337:0:5::/64"
# File lib/ipaddress_2/ipv6.rb, line 449 def advance_network(amount) IPAddress::IPv6.parse_u128(self.network.to_i + amount*self.size, @prefix) end
Allocates a new ip from the current subnet. Optional skip parameter can be used to skip addresses.
Will raise StopIteration exception when all addresses have been allocated
Example:
ip = IPAddress("10.0.0.0/24") ip.allocate #=> "10.0.0.1/24" ip.allocate #=> "10.0.0.2/24" ip.allocate(2) #=> "10.0.0.5/24"
Uses an internal @allocator which tracks the state of allocated addresses.
# File lib/ipaddress_2/ipv6.rb, line 1155 def allocate(skip=0) @allocator += 1 + skip next_ip = network_u128+@allocator if next_ip > broadcast_u128 raise StopIteration end self.class.parse_u128(next_ip, @prefix) end
When serializing to JSON format, just use the string representation
ip = IPAddress "2001:db8::8:800:200c:417a/64" ip.as_json #=> "2001:db8::8:800:200c:417a/64"
# File lib/ipaddress_2/ipv6.rb, line 129 def as_json to_string 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") ip6.bits #=> "0010000000000001000011011011100000 [...] "
# File lib/ipaddress_2/ipv6.rb, line 905 def bits data.unpack("B*").first end
Returns the broadcast address for the given IP. As this is IPv6
it is just the last IP
ip = IPAddress("2001:db8:8:800::/64") ip.broadcast.to_s #=> "2001:db8:8:800::"
# File lib/ipaddress_2/ipv6.rb, line 963 def broadcast if prefix == 128 return self else IPAddress::IPv6::parse_u128(broadcast_u128) end 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.
# File lib/ipaddress_2/ipv6.rb, line 583 def broadcast_u128 network_u128 + size - 1 end
Compressed form of the IPv6
address
ip6 = IPAddress "2001:db8::8:800:200c:417a/64" ip6.compressed #=> "2001:db8::8:800:200c:417a"
# File lib/ipaddress_2/ipv6.rb, line 652 def compressed @compressed end
Returns the address portion of an IPv6
object in a network byte order format.
ip6 = IPAddress "2001:db8::8:800:200c:417a/64" ip6.data #=> " \001\r\270\000\000\000\000\000\b\b\000 \fAz"
It is usually used to include an IP address in a data packet to be sent over a socket
a = Socket.open(params) # socket details here ip6 = IPAddress "2001:db8::8:800:200c:417a/64" binary_data = ["Address: "].pack("a*") + ip.data # Send binary data a.puts binary_data
# File lib/ipaddress_2/ipv6.rb, line 365 def data @groups.pack("n8") 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!
# File lib/ipaddress_2/ipv6.rb, line 823 def each (network_u128..broadcast_u128).each do |i| yield self.class.parse_u128(i, @prefix) end end
Finds the adjacent block to a subnet.
Example:
ip = IPAddress("2001:db8::/32") ip.find_adjacent_subnet #=> "2001:db9::/32"
# File lib/ipaddress_2/ipv6.rb, line 1174 def find_adjacent_subnet return false if prefix == 0 current_subnet = to_string self.prefix = @prefix - 1 adjacent_subnet = (split.map{|i| i.to_string} - [current_subnet])[0] self.prefix = @prefix + 1 return adjacent_subnet end
Returns a new IPv6
object with the first host IP address in the range.
Example: given the 2001:db8:8:800::/64 network, the first
- host IP address is 2001:db8:8:800
-
ip = IPAddress(“2001:db8:8:800::/64”)
ip.first.to_s
#=> "2001:db8:8:800::"
The object IP doesn't need to be a network: the method automatically gets the network number from it
ip = IPAddress("2001:db8:9:800::2/64") ip.first.to_s #=> "2001:db8:9:800::"
# File lib/ipaddress_2/ipv6.rb, line 269 def first if prefix == 128 return self else IPAddress::IPv6::parse_u128(network_u128) end end
Returns an array with the 16 bits groups in decimal format:
ip6 = IPAddress "2001:db8::8:800:200c:417a/64" ip6.groups #=> [8193, 3512, 0, 0, 8, 2048, 8204, 16762]
# File lib/ipaddress_2/ipv6.rb, line 142 def groups @groups end
Returns an array of the 16 bits groups in hexdecimal format:
ip6 = IPAddress "2001:db8::8:800:200c:417a/64" ip6.hexs #=> ["2001", "0db8", "0000", "0000", "0008", "0800", "200c", "417a"]
Not to be confused with the similar IPv6#to_hex
method.
# File lib/ipaddress_2/ipv6.rb, line 380 def hexs @address.split(":") end
Returns a new IPv6
object containing only the host part of this IP.
ip = IPAddress::IPv6.new("fc42:1337:0:5::7/64") ip.hostpart.to_s #=> "::7"
# File lib/ipaddress_2/ipv6.rb, line 497 def hostpart self.class.parse_u128(hostpart_u128, 128) end
Returns this address' host part in unsigned 128bits format
ip = IPAddress::IPv6.new("fc42:1337:0:5::7/64") ip.host_u128 #=> 7
# File lib/ipaddress_2/ipv6.rb, line 567 def hostpart_u128 to_u128 & ~@prefix.to_u128 end
Checks whether a subnet includes the given IP address.
Example:
ip6 = IPAddress "2001:db8::8:800:200c:417a/64" addr = IPAddress "2001:db8::8:800:200c:1/128" ip6.include? addr #=> true ip6.include? IPAddress("2001:db8:1::8:800:200c:417a/76") #=> false ip6.include? "2001:db8::8:800:200c:1" #=> true
# File lib/ipaddress_2/ipv6.rb, line 618 def include?(oth) unless oth.is_a? IPAddress::IPv6 oth = IPv6.new(oth) end @prefix <= oth.prefix and network_u128 == self.class.new(oth.address+"/#@prefix").network_u128 end
Checks whether a subnet includes all the given IPv4
objects or strings.
ip = IPAddress("2001:db8:8:800::1/64") addr1 = IPAddress("2001:db8:8:800::2/64") addr2 = IPAddress("2001:db8:8:800::8/64") ip.include_all?(addr1,addr2) #=> true ip.include_all?("2001:db8:8:800::2/64", "2001:db8:8:800::8/64") #=> true
# File lib/ipaddress_2/ipv6.rb, line 640 def include_all?(*others) others.all? {|oth| include?(oth)} end
Like its sibling method IPv4#first
, this method returns a new IPv4
object with the last host IP address in the range.
Example: given the 192.168.100.0/24 network, the last host IP address is 192.168.100.254
ip = IPAddress("2001:db8:8:800::/64") ip.last.to_s #=> "2001:db8:8:800:ffff:ffff:ffff:ffff"
The object IP doesn't need to be a network: the method automatically gets the network number from it
ip = IPAddress("2001:db8:9:800::2/64") ip.last.to_s #=> "2001:db8:9:800:ffff:ffff:ffff:ffff"
# File lib/ipaddress_2/ipv6.rb, line 298 def last if prefix == 128 return self else IPAddress::IPv6::parse_u128(broadcast_u128) end end
Checks if an IPv6
address objects belongs to a link-local network RFC4291
Example:
ip = IPAddress "fe80::1" ip.link_local? #=> true
# File lib/ipaddress_2/ipv6.rb, line 684 def link_local? [self.class.new("fe80::/10")].any? {|i| i.include? self} end
Literal version of the IPv6
address
ip6 = IPAddress "2001:db8::8:800:200c:417a/64" ip6.literal #=> "2001-0db8-0000-0000-0008-0800-200c-417a.ipv6-literal.net"
# File lib/ipaddress_2/ipv6.rb, line 937 def literal @address.gsub(":","-") + ".ipv6-literal.net" end
Returns true if the address is a loopback address
See IPAddress::IPv6::Loopback
for more information
# File lib/ipaddress_2/ipv6.rb, line 670 def loopback? @prefix == 128 and @compressed == "::1" end
Returns true if the address is a mapped address
See IPAddress::IPv6::Mapped
for more information
# File lib/ipaddress_2/ipv6.rb, line 707 def mapped? to_u128 >> 32 == 0xffff 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"
# File lib/ipaddress_2/ipv6.rb, line 950 def network self.class.parse_u128(network_u128, @prefix) end
True if the IPv6
address is a network
ip6 = IPAddress "2001:db8::8:800:200c:417a/64" ip6.network? #=> false ip6 = IPAddress "2001:db8:8:800::/64" ip6.network? #=> true
# File lib/ipaddress_2/ipv6.rb, line 245 def network? to_u128 | @prefix.to_u128 == @prefix.to_u128 end
Returns the network number in Unsigned 128bits format
ip6 = IPAddress "2001:db8::8:800:200c:417a/64" ip6.network_u128 #=> 42540766411282592856903984951653826560
# File lib/ipaddress_2/ipv6.rb, line 555 def network_u128 to_u128 & @prefix.to_u128 end
Returns the network address of the network succeeding this one.
Example:
ip = IPAddress::IPv6.new("fc42:1337:0:0::/64") ip.next_network.to_string #=> "fc42:1337:0:1::/64"
# File lib/ipaddress_2/ipv6.rb, line 461 def next_network advance_network 1 end
Returns the predecessor to the IP address
Example:
ip6 = IPAddress("2001:db8::8:800:200c:417a/64") ip6.pred.to_string => "2001:db8::8:800:200c:4179/64"
# File lib/ipaddress_2/ipv6.rb, line 854 def pred IPAddress::IPv6.parse_u128(to_u128.pred, prefix) end
Returns an instance of the prefix object
ip6 = IPAddress "2001:db8::8:800:200c:417a/64" ip6.prefix #=> 64
# File lib/ipaddress_2/ipv6.rb, line 154 def prefix @prefix end
Set a new prefix number for the object
This is useful if you want to change the prefix to an object created with IPv6::parse_u128
or if the object was created using the default prefix of 128 bits.
ip6 = IPAddress("2001:db8::8:800:200c:417a") puts ip6.to_string #=> "2001:db8::8:800:200c:417a/128" ip6.prefix = 64 puts ip6.to_string #=> "2001:db8::8:800:200c:417a/64"
# File lib/ipaddress_2/ipv6.rb, line 175 def prefix=(num) @prefix = Prefix128.new(num) end
Returns the network address of the network preceeding this one.
Example:
ip = IPAddress::IPv6.new("fc42:1337:0:5::/64") ip.previous_network.to_string #=> "fc42:1337:0:4::/64"
# File lib/ipaddress_2/ipv6.rb, line 485 def previous_network regress_network 1 end
Returns the network address of the n-th network preceeding this one.
Example:
ip = IPAddress::IPv6.new("fc42:1337:0:5::/64") ip.regress_network(4).to_string #=> "fc42:1337:0:1::/64"
# File lib/ipaddress_2/ipv6.rb, line 473 def regress_network(amount) advance_network(-amount) end
Returns the IPv6
address in a DNS reverse lookup string, as per RFC3172 and RFC2874.
ip6 = IPAddress "3ffe:505:2::f" ip6.reverse #=> "f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.arpa"
# File lib/ipaddress_2/ipv6.rb, line 393 def reverse to_hex.reverse.gsub(/./){|c| c+"."} + "ip6.arpa" 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
# File lib/ipaddress_2/ipv6.rb, line 597 def size 2 ** @prefix.host_prefix end
Splits a network into different subnets
NOTE: Will allow you to split past /64 against RFC 5375
If the IP Address is a network, it can be divided into 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.
network = IPAddress("2001:db8:8::/48") network / 4 # implies map{|i| i.to_string} #=> ["2001:db8:8::/50", #=> "2001:db8:8:4000::/50", #=> "2001:db8:8:8000::/50", #=> "2001:db8:8:c000::/50"]
If num
is any other number, the supernet will be divided into some networks with a even number of hosts and other networks with the remaining addresses.
network = IPAddress("2001:db8:8::/48") network / 3 # implies map{|i| i.to_string} #=> ["2001:db8:8::/50", #=> "2001:db8:8:4000::/50", #=> "2001:db8:8:8000::/49"]
Returns an array of IPv6
objects
# File lib/ipaddress_2/ipv6.rb, line 535 def split(subnets=2) unless (1..(2**@prefix.host_prefix)).include? subnets raise ArgumentError, "Value #{subnets} out of range" end networks = subnet(newprefix(subnets)) until networks.size == subnets networks = sum_first_found(networks) end return networks 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.subnet(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.
# File lib/ipaddress_2/ipv6.rb, line 789 def subnet(subprefix) unless ((@prefix.to_i)..128).include? subprefix raise ArgumentError, "New prefix must be between #@prefix and 128" end Array.new(2**(subprefix-@prefix.to_i)) do |i| self.class.parse_u128(network_u128+(i*(2**(128-subprefix))), subprefix) end end
Returns a new IPv6
object which is the result of decreasing this IP address by a given value. In other words, this arithmetically subtracts IP addresses.
Will raise an error if the resulting address is in a different subnet, except validating is set to false.
Example:
ip = IPAddress::IPv6.new("fc42:1337::a/64") ip.subtract(5).to_string #=> "fc42:1337::5/64"
# File lib/ipaddress_2/ipv6.rb, line 436 def subtract(oth, validating=true) oth = oth.to_i if oth.kind_of? IPAddress::IPv6 # oth shall be integer add(-oth, validating) end
Returns the successor to the IP address
Example:
ip6 = IPAddress("2001:db8::8:800:200c:417a/64") ip6.succ.to_string => "2001:db8::8:800:200c:417b/64"
# File lib/ipaddress_2/ipv6.rb, line 839 def succ IPAddress::IPv6.parse_u128(to_u128.succ, prefix) end
Returns a new IPv4
object from the supernetting of the instance network.
Supernetting is similar to subnetting, except that you getting as a result a network with a smaller prefix (bigger host space). For example, given the network
ip = IPAddress("2001:db8:8:800::1/64")
you can supernet it with a new /32 prefix
ip.supernet(32).to_string #=> "2001:db8::/32"
However if you supernet it with a /22 prefix, the network address will change:
ip.supernet(22).to_string #=> "2001:c00::/22"
If new_prefix
is less than 1, returns 0000:0000:0000:0000:0000:0000:0000:0000/0
# File lib/ipaddress_2/ipv6.rb, line 761 def supernet(new_prefix) raise ArgumentError, "New prefix must be smaller than existing prefix" if new_prefix >= @prefix.to_i return self.class.new("0000:0000:0000:0000:0000:0000:0000:0000/0") if new_prefix < 1 return self.class.new(@address+"/#{new_prefix}").network end
Returns a Base16 number representing the IPv6
address
ip6 = IPAddress "2001:db8::8:800:200c:417a/64" ip6.to_hex #=> "20010db80000000000080800200c417a"
# File lib/ipaddress_2/ipv6.rb, line 343 def to_hex hexs.join("") end
Returns a decimal format (unsigned 128 bit) of the IPv6
address
ip6 = IPAddress "2001:db8::8:800:200c:417a/64" ip6.to_i #=> 42540766411282592856906245548098208122
# File lib/ipaddress_2/ipv6.rb, line 227 def to_i to_hex.hex end
Returns the IPv6
address in a human readable form, using the compressed address.
ip6 = IPAddress "2001:db8::8:800:200c:417a/64" ip6.to_s #=> "2001:db8::8:800:200c:417a"
# File lib/ipaddress_2/ipv6.rb, line 214 def to_s @compressed end
Returns the IPv6
address in a human readable form, using the compressed address.
ip6 = IPAddress "2001:0db8:0000:0000:0008:0800:200c:417a/64" ip6.to_string #=> "2001:db8::8:800:200c:417a/64"
# File lib/ipaddress_2/ipv6.rb, line 201 def to_string "#@compressed/#@prefix" end
Unlike its counterpart IPv6#to_string
method, IPv6#to_string_uncompressed
returns the whole IPv6
address and prefix in an uncompressed form
ip6 = IPAddress "2001:db8::8:800:200c:417a/64" ip6.to_string_uncompressed #=> "2001:0db8:0000:0000:0008:0800:200c:417a/64"
# File lib/ipaddress_2/ipv6.rb, line 188 def to_string_uncompressed "#@address/#@prefix" end
Checks if an IPv6
address objects belongs to a unique-local network RFC4193
Example:
ip = IPAddress "fc00::1" ip.unique_local? #=> true
# File lib/ipaddress_2/ipv6.rb, line 698 def unique_local? [self.class.new("fc00::/7")].any? {|i| i.include? self} end
Returns true if the address is an unspecified address
See IPAddress::IPv6::Unspecified
for more information
# File lib/ipaddress_2/ipv6.rb, line 661 def unspecified? @prefix == 128 and @compressed == "::" end
Private Instance Methods
# File lib/ipaddress_2/ipv6.rb, line 1216 def aggregate(ip1,ip2) return [ip1] if ip1.include? ip2 snet = ip1.supernet(ip1.prefix-1) if snet.include_all?(ip1, ip2) && ((ip1.size + ip2.size) == snet.size) return [snet] else return [ip1, ip2] end end
# File lib/ipaddress_2/ipv6.rb, line 1201 def compress_address str = @groups.map{|i| i.to_s 16}.join ":" loop do break if str.sub!(/\A0:0:0:0:0:0:0:0\Z/, '::') break if str.sub!(/\b0:0:0:0:0:0:0\b/, ':') break if str.sub!(/\b0:0:0:0:0:0\b/, ':') break if str.sub!(/\b0:0:0:0:0\b/, ':') break if str.sub!(/\b0:0:0:0\b/, ':') break if str.sub!(/\b0:0:0\b/, ':') break if str.sub!(/\b0:0\b/, ':') break end str.sub(/:{3,}/, '::') end
# File lib/ipaddress_2/ipv6.rb, line 1185 def newprefix(num) return @prefix + (Math::log2(num).ceil ) end
# File lib/ipaddress_2/ipv6.rb, line 1189 def sum_first_found(arr) dup = arr.dup.reverse dup.each_with_index do |obj,i| a = [self.class.summarize(obj,dup[i+1])].flatten if a.size == 1 dup[i..i+1] = a return dup.reverse end end return dup.reverse end