Class: IPAddress::IPv6

Inherits:
Object
  • Object
show all
Includes:
Comparable, Enumerable, IPAddress
Defined in:
lib/ipaddress_2/ipv6.rb

Overview

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.

Direct Known Subclasses

Loopback, Mapped, Unspecified

Defined Under Namespace

Classes: Loopback, Mapped, Unspecified

Constant Summary collapse

IN6FORMAT =

Format string to pretty print IPv6 addresses

("%.4x:"*8).chop

Constants included from IPAddress

AUTHORS, GEM, NAME, VERSION

Class Method Summary collapse

Instance Method Summary collapse

Methods included from IPAddress

demongoize, deprecate, evolve, #ipv4?, #ipv6?, mongoize, #mongoize, ntoa, parse, valid?, valid_ip?, valid_ipv4?, valid_ipv4_netmask?, valid_ipv4_subnet?, valid_ipv6?, valid_ipv6_subnet?

Constructor Details

#initialize(str) ⇒ IPv6

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"

Raises:

  • (ArgumentError)


89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# 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

Class Method Details

.compress(str) ⇒ Object

Compress an IPv6 address in its compressed form

IPAddress::IPv6.compress "2001:0DB8:0000:CD30:0000:0000:0000:0000"
  #=> "2001:db8:0:cd30::"


925
926
927
# File 'lib/ipaddress_2/ipv6.rb', line 925

def self.compress(str)
  self.new(str).compressed
end

.expand(str) ⇒ Object

Expands an IPv6 address in the canocical form

IPAddress::IPv6.expand "2001:0DB8:0:CD30::"
  #=> "2001:0DB8:0000:CD30:0000:0000:0000:0000"


915
916
917
# File 'lib/ipaddress_2/ipv6.rb', line 915

def self.expand(str)
  self.new(str).address
end

.groups(str) ⇒ Object

Extract 16 bits groups from a string



974
975
976
977
978
979
980
981
# 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

.parse_data(str) ⇒ Object

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"


1003
1004
1005
# File 'lib/ipaddress_2/ipv6.rb', line 1003

def self.parse_data(str)
  self.new(IN6FORMAT % str.unpack("n8"))
end

.parse_hex(hex, prefix = 128) ⇒ Object

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"


1046
1047
1048
# File 'lib/ipaddress_2/ipv6.rb', line 1046

def self.parse_hex(hex, prefix=128)
  self.parse_u128(hex.hex, prefix)
end

.parse_u128(u128, prefix = 128) ⇒ Object

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"


1024
1025
1026
1027
# 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

.summarize(*args) ⇒ Object

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"]


1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
# 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

Instance Method Details

#+(oth) ⇒ Object

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"]


733
734
735
# File 'lib/ipaddress_2/ipv6.rb', line 733

def +(oth)
  aggregate(*[self,oth].sort.map{|i| i.network})
end

#<=>(oth) ⇒ Object

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"]


890
891
892
893
894
# 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

#[](index) ⇒ Object Also known as: group

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


320
321
322
# File 'lib/ipaddress_2/ipv6.rb', line 320

def [](index)
  @groups[index]
end

#[]=(index, value) ⇒ Object Also known as: group=

Updated the octet specified at index



328
329
330
331
# File 'lib/ipaddress_2/ipv6.rb', line 328

def []=(index, value)
  @groups[index] = value
  initialize("#{IN6FORMAT % @groups}/#{prefix}")
end

#add(oth, validating = true) ⇒ Object

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"


411
412
413
414
415
416
417
418
419
420
421
# 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

#addressObject

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"


118
119
120
# File 'lib/ipaddress_2/ipv6.rb', line 118

def address
  @address
end

#advance_network(amount) ⇒ Object

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"


449
450
451
# 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

#allocate(skip = 0) ⇒ Object

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.



1155
1156
1157
1158
1159
1160
1161
1162
1163
# 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

#as_jsonObject

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"


129
130
131
# File 'lib/ipaddress_2/ipv6.rb', line 129

def as_json
  to_string
end

#bitsObject

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 [...] "


905
906
907
# File 'lib/ipaddress_2/ipv6.rb', line 905

def bits
  data.unpack("B*").first
end

#broadcastObject

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::"


963
964
965
966
967
968
969
# File 'lib/ipaddress_2/ipv6.rb', line 963

def broadcast
  if prefix == 128
    return self
  else
    IPAddress::IPv6::parse_u128(broadcast_u128)
  end
end

#broadcast_u128Object

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.



583
584
585
# File 'lib/ipaddress_2/ipv6.rb', line 583

def broadcast_u128
  network_u128 + size - 1
end

#compressedObject

Compressed form of the IPv6 address

ip6 = IPAddress "2001:db8::8:800:200c:417a/64"

ip6.compressed
  #=> "2001:db8::8:800:200c:417a"


652
653
654
# File 'lib/ipaddress_2/ipv6.rb', line 652

def compressed
  @compressed
end

#dataObject

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


365
366
367
# File 'lib/ipaddress_2/ipv6.rb', line 365

def data
  @groups.pack("n8")
end

#eachObject

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!



823
824
825
826
827
# 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

#find_adjacent_subnetObject

Finds the adjacent block to a subnet.

Example:

ip = IPAddress("2001:db8::/32")
ip.find_adjacent_subnet
  #=> "2001:db9::/32"


1174
1175
1176
1177
1178
1179
1180
1181
# 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

#firstObject

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::"


269
270
271
272
273
274
275
# File 'lib/ipaddress_2/ipv6.rb', line 269

def first
  if prefix == 128
    return self
  else
    IPAddress::IPv6::parse_u128(network_u128)
  end
end

#groupsObject

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]


142
143
144
# File 'lib/ipaddress_2/ipv6.rb', line 142

def groups
  @groups
end

#hexsObject

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.



380
381
382
# File 'lib/ipaddress_2/ipv6.rb', line 380

def hexs
  @address.split(":")
end

#hostpartObject

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"


497
498
499
# File 'lib/ipaddress_2/ipv6.rb', line 497

def hostpart
  self.class.parse_u128(hostpart_u128, 128)
end

#hostpart_u128Object

Returns this address’ host part in unsigned 128bits format

ip = IPAddress::IPv6.new("fc42:1337:0:5::7/64")

ip.host_u128
  #=> 7


567
568
569
# File 'lib/ipaddress_2/ipv6.rb', line 567

def hostpart_u128
  to_u128 & ~@prefix.to_u128
end

#include?(oth) ⇒ Boolean

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

Returns:

  • (Boolean)


618
619
620
621
622
623
# 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

#include_all?(*others) ⇒ Boolean

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

Returns:

  • (Boolean)


640
641
642
# File 'lib/ipaddress_2/ipv6.rb', line 640

def include_all?(*others)
  others.all? {|oth| include?(oth)}
end

#lastObject

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"


298
299
300
301
302
303
304
# 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

Returns:

  • (Boolean)


684
685
686
# File 'lib/ipaddress_2/ipv6.rb', line 684

def link_local?
  [self.class.new("fe80::/10")].any? {|i| i.include? self}
end

#literalObject

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"


937
938
939
# File 'lib/ipaddress_2/ipv6.rb', line 937

def literal
  @address.gsub(":","-") + ".ipv6-literal.net"
end

#loopback?Boolean

Returns true if the address is a loopback address

See IPAddress::IPv6::Loopback for more information

Returns:

  • (Boolean)


670
671
672
# File 'lib/ipaddress_2/ipv6.rb', line 670

def loopback?
  @prefix == 128 and @compressed == "::1"
end

#mapped?Boolean

Returns true if the address is a mapped address

See IPAddress::IPv6::Mapped for more information

Returns:

  • (Boolean)


707
708
709
# File 'lib/ipaddress_2/ipv6.rb', line 707

def mapped?
  to_u128 >> 32 == 0xffff
end

#networkObject

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"


950
951
952
# File 'lib/ipaddress_2/ipv6.rb', line 950

def network
  self.class.parse_u128(network_u128, @prefix)
end

#network?Boolean

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

Returns:

  • (Boolean)


245
246
247
# File 'lib/ipaddress_2/ipv6.rb', line 245

def network?
  to_u128 | @prefix.to_u128 == @prefix.to_u128
end

#network_u128Object

Returns the network number in Unsigned 128bits format

ip6 = IPAddress "2001:db8::8:800:200c:417a/64"

ip6.network_u128
  #=> 42540766411282592856903984951653826560


555
556
557
# File 'lib/ipaddress_2/ipv6.rb', line 555

def network_u128
  to_u128 & @prefix.to_u128
end

#next_networkObject

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"


461
462
463
# File 'lib/ipaddress_2/ipv6.rb', line 461

def next_network
  advance_network 1
end

#predObject

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"


854
855
856
# File 'lib/ipaddress_2/ipv6.rb', line 854

def pred
  IPAddress::IPv6.parse_u128(to_u128.pred, prefix)
end

#prefixObject

Returns an instance of the prefix object

ip6 = IPAddress "2001:db8::8:800:200c:417a/64"

ip6.prefix
  #=> 64


154
155
156
# File 'lib/ipaddress_2/ipv6.rb', line 154

def prefix
  @prefix
end

#prefix=(num) ⇒ Object

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"


175
176
177
# File 'lib/ipaddress_2/ipv6.rb', line 175

def prefix=(num)
  @prefix = Prefix128.new(num)
end

#previous_networkObject

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"


485
486
487
# File 'lib/ipaddress_2/ipv6.rb', line 485

def previous_network
  regress_network 1
end

#regress_network(amount) ⇒ Object

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"


473
474
475
# File 'lib/ipaddress_2/ipv6.rb', line 473

def regress_network(amount)
  advance_network(-amount)
end

#reverseObject Also known as: arpa

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"


393
394
395
# File 'lib/ipaddress_2/ipv6.rb', line 393

def reverse
  to_hex.reverse.gsub(/./){|c| c+"."} + "ip6.arpa"
end

#sizeObject

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


597
598
599
# File 'lib/ipaddress_2/ipv6.rb', line 597

def size
  2 ** @prefix.host_prefix
end

#split(subnets = 2) ⇒ Object Also known as: /

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



535
536
537
538
539
540
541
542
543
544
# 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

#subnet(subprefix) ⇒ Object

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.



789
790
791
792
793
794
795
796
# 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

#subtract(oth, validating = true) ⇒ Object

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"


436
437
438
439
# 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

#succObject Also known as: next

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"


839
840
841
# File 'lib/ipaddress_2/ipv6.rb', line 839

def succ
  IPAddress::IPv6.parse_u128(to_u128.succ, prefix)
end

#supernet(new_prefix) ⇒ Object

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

Raises:

  • (ArgumentError)


761
762
763
764
765
# 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

#to_hexObject

Returns a Base16 number representing the IPv6 address

ip6 = IPAddress "2001:db8::8:800:200c:417a/64"

ip6.to_hex
  #=> "20010db80000000000080800200c417a"


343
344
345
# File 'lib/ipaddress_2/ipv6.rb', line 343

def to_hex
  hexs.join("")
end

#to_iObject Also known as: to_u128

Returns a decimal format (unsigned 128 bit) of the IPv6 address

ip6 = IPAddress "2001:db8::8:800:200c:417a/64"

ip6.to_i
  #=> 42540766411282592856906245548098208122


227
228
229
# File 'lib/ipaddress_2/ipv6.rb', line 227

def to_i
  to_hex.hex
end

#to_sObject

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"


214
215
216
# File 'lib/ipaddress_2/ipv6.rb', line 214

def to_s
  @compressed
end

#to_stringObject

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"


201
202
203
# File 'lib/ipaddress_2/ipv6.rb', line 201

def to_string
  "#@compressed/#@prefix"
end

#to_string_uncompressedObject

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"


188
189
190
# File 'lib/ipaddress_2/ipv6.rb', line 188

def to_string_uncompressed
  "#@address/#@prefix"
end

#unique_local?Boolean

Checks if an IPv6 address objects belongs to a unique-local network RFC4193

Example:

ip = IPAddress "fc00::1"
ip.unique_local?
  #=> true

Returns:

  • (Boolean)


698
699
700
# File 'lib/ipaddress_2/ipv6.rb', line 698

def unique_local?
  [self.class.new("fc00::/7")].any? {|i| i.include? self}
end

#unspecified?Boolean

Returns true if the address is an unspecified address

See IPAddress::IPv6::Unspecified for more information

Returns:

  • (Boolean)


661
662
663
# File 'lib/ipaddress_2/ipv6.rb', line 661

def unspecified?
  @prefix == 128 and @compressed == "::"
end