Class: IPAddress::IPv6

Inherits:
IPAddress show all
Defined in:
lib/ipaddress/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

RE =

Regular expression to match an IPv6 address

%r{ #{part4} (?: : #{IPv4::INTERNAL_RE} )? \z }xo
IN6FORMAT =

Format string to pretty print IPv6 addresses

Array.new(8, '%.4x').join(':')
Prefix =
Prefix128
MAX_PREFIX =
Prefix::MAX

Constants inherited from IPAddress

AUTHORS, GEM, NAME, VERSION

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from IPAddress

#<=>, #at, #bits, #boundaries, #broadcast, #broadcast_i, #distance, #each, #each_host, #each_i, #exact_supernet, #first, #hash, #hosts, #include?, #include_all?, #include_exactly?, #inspect, #ipv4?, #ipv6?, #last, #mapped, #network, #network?, #network_i, #new_prefix, #overlap?, #overlap_i?, parse, #proper_supernet, #range, #size, #span, #span_i, #split, #subnet, subtract, #subtract, subtract!, #succ, #summarize, summarize, #supernet, #to_string, valid?, valid_ipv4?, valid_ipv4_netmask?, valid_ipv6?

Methods included from Conversions

#addr2ary, #addr2bits, #ary2addr, #ary2data, #ary2int, #bits2addr, #data2ary, #data2bits, #data2int, #int2addr, #int2ary, #int2data

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


200
201
202
203
204
205
206
# File 'lib/ipaddress/ipv6.rb', line 200

def initialize(str)
  unless str =~ /:.+\./
    @ip, @netmask = split_ip_and_netmask(str)
  else
    raise ArgumentError, "Use #{self.class}::Mapped for IPv4 mapped addresses"
  end
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::"


170
171
172
# File 'lib/ipaddress/ipv6.rb', line 170

def compress(str)
  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"


160
161
162
# File 'lib/ipaddress/ipv6.rb', line 160

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

.groups(str) ⇒ Object

Extract 16 bits groups from a string



177
178
179
180
# File 'lib/ipaddress/ipv6.rb', line 177

def groups(str)
  l, r = str.split('::', 2).map! { |i| i.split(':').map! { |j| j.hex } }
  l.concat(Array.new(8 - l.size - (r ||= []).size, 0)).concat(r)
end

.parse_data(str, prefix = MAX_PREFIX) ⇒ 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", 64)

ip6.to_s
  #=> "2001:db8::8:800:200c:417a/64"


130
131
132
# File 'lib/ipaddress/ipv6.rb', line 130

def parse_data(str, prefix = MAX_PREFIX)
  instantiate { @groups, @netmask = str.unpack('n8'), prefix }
end

.parse_hex(hex, prefix = MAX_PREFIX) ⇒ Object

Creates a new IPv6 object from a number expressed in hexdecimal format:

ip6 = IPAddress::IPv6.parse_hex("20010db80000000000080800200c417a")

ip6.to_string
  #=> "2001:db8::8:800:200c:417a/128"

The prefix parameter is optional:

ip6 = IPAddress::IPv6.parse_hex("20010db80000000000080800200c417a", 64)

ip6.to_string
  #=> "2001:db8::8:800:200c:417a/64"


150
151
152
# File 'lib/ipaddress/ipv6.rb', line 150

def parse_hex(hex, prefix = MAX_PREFIX)
  parse_i(hex.hex, prefix)
end

.parse_i(i, prefix = MAX_PREFIX) ⇒ Object Also known as: parse_u128

Creates a new IPv6 object from an unsigned 128 bits integer.

ip6 = IPAddress::IPv6.parse_u128(42540766411282592856906245548098208122)

ip6.to_string
  #=> "2001:db8::8:800:200c:417a/128"

The prefix parameter is optional:

ip6 = IPAddress::IPv6.parse_u128(42540766411282592856906245548098208122, 64)

ip6.to_string
  #=> "2001:db8::8:800:200c:417a/64"


104
105
106
107
# File 'lib/ipaddress/ipv6.rb', line 104

def parse_i(i, prefix = MAX_PREFIX)
  groups = Array.new(8) { |j| i >> (112 - 16 * j) & 0xffff }
  instantiate { @groups, @netmask = groups, prefix }
end

Instance Method Details

#[](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


375
376
377
# File 'lib/ipaddress/ipv6.rb', line 375

def [](index)
  groups[index]
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"


220
221
222
# File 'lib/ipaddress/ipv6.rb', line 220

def address
  lazy_attr(:address) { IN6FORMAT % groups }
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"


232
233
234
235
236
237
238
239
240
241
242
# File 'lib/ipaddress/ipv6.rb', line 232

def compressed
  lazy_attr(:compressed) {
    r1, r2, q = /\b0(?::0)+\b/, /:{3,}/, '::'

    a, b = [s = groups.map { |i| i.to_s(16) }.join(':'), s.reverse].map! { |t|
      t.sub!(r1, q) && t.sub!(r2, q) || t
    }

    a.length > b.length ? b.reverse! : a
  }
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


357
358
359
# File 'lib/ipaddress/ipv6.rb', line 357

def data
  lazy_attr(:data) { groups.pack('n8') }
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]


265
266
267
# File 'lib/ipaddress/ipv6.rb', line 265

def groups
  lazy_attr(:groups) { self.class.groups(@ip) }
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.



280
281
282
# File 'lib/ipaddress/ipv6.rb', line 280

def hexs
  lazy_attr(:hexs) { address.split(':') }
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"


408
409
410
# File 'lib/ipaddress/ipv6.rb', line 408

def literal
  lazy_attr(:literal) { "#{address.tr(':', '-')}.ipv6-literal.net" }
end

#loopback?Boolean

Returns true if the address is a loopback address

See IPAddress::IPv6::Loopback for more information

Returns:

  • (Boolean)


426
427
428
# File 'lib/ipaddress/ipv6.rb', line 426

def loopback?
  lazy_attr(:loopback_p) { prefix.max? && compressed == '::1' }
end

#mapped?Boolean

Returns true if the address is a mapped address

See IPAddress::IPv6::Mapped for more information

Returns:

  • (Boolean)


435
436
437
# File 'lib/ipaddress/ipv6.rb', line 435

def mapped?
  lazy_attr(:mapped_p) { to_i >> 32 == 0xffff }
end

#prefixObject

Returns an instance of the prefix object

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

ip6.prefix
  #=> 64


252
253
254
# File 'lib/ipaddress/ipv6.rb', line 252

def prefix
  lazy_attr(:prefix, false) { Prefix.new(@netmask) }
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"


394
395
396
# File 'lib/ipaddress/ipv6.rb', line 394

def reverse
  lazy_attr(:reverse) { "#{to_hex.gsub(/(?=.)/, '.').reverse}ip6.arpa" }
end

#to_hexObject

Returns a Base16 number representing the IPv6 address

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

ip6.to_hex
  #=> "20010db80000000000080800200c417a"


293
294
295
# File 'lib/ipaddress/ipv6.rb', line 293

def to_hex
  lazy_attr(:to_hex) { hexs.join('') }
end

#to_iObject Also known as: u128, 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


332
333
334
# File 'lib/ipaddress/ipv6.rb', line 332

def to_i
  lazy_attr(:int) { 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"


306
307
308
# File 'lib/ipaddress/ipv6.rb', line 306

def to_s
  compressed
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"


319
320
321
# File 'lib/ipaddress/ipv6.rb', line 319

def to_string_uncompressed
  "#{address}/#{prefix}"
end

#unspecified?Boolean

Returns true if the address is an unspecified address

See IPAddress::IPv6::Unspecified for more information

Returns:

  • (Boolean)


417
418
419
# File 'lib/ipaddress/ipv6.rb', line 417

def unspecified?
  lazy_attr(:unspecified_p) { prefix.max? && compressed == '::' }
end

#versionObject



208
209
210
# File 'lib/ipaddress/ipv6.rb', line 208

def version
  6
end