Socket::IPAddress - Crystal 1.20.1

# struct Socket::IPAddress

- Socket::IPAddress
- Socket::Address
- Struct
- Value
- Object

##
Overview

IP address representation.

Holds a binary representation of an IP address, either translated from a `String`, or directly received from an opened connection (e.g. `Socket#local_address`, `Socket#receive`).

`IPAddress` won't resolve domains, including `localhost`. If you must resolve an IP, or don't know whether a `String` contains an IP or a domain name, you should use `Addrinfo.resolve` instead.

##
Defined in:

socket/address.cr

##
Constant Summary

BROADCAST = `"255.255.255.255"`
BROADCAST6 = `"ff0X::1"`
LOOPBACK = `"127.0.0.1"`
LOOPBACK6 = `"::1"`
UNSPECIFIED = `"0.0.0.0"`
UNSPECIFIED6 = `"::"`

##
Constructors

- .from(sockaddr : Pointer(LibC::Sockaddr), addrlen) : IPAddress

  Creates an `IPAddress` from the internal OS representation.

- .from(sockaddr : Pointer(LibC::Sockaddr)) : IPAddress

  Creates an `IPAddress` from the internal OS representation.

- .new(address : String, port : Int32)

  Creates an `IPAddress` from the given IPv4 or IPv6 address and port number.

- .parse(uri : URI) : IPAddress

  Parses a `Socket::IPAddress` from an URI.

- .parse(uri : String) : self

  Parses a `Socket::IPAddress` from an URI.

- .v4(x0 : Int, x1 : Int, x2 : Int, x3 : Int, *, port : Int) : self

  Returns the IPv4 address `x0.x1.x2.x3:port`.

- .v4(fields : StaticArray(UInt8, 4), port : UInt16) : self

  Returns the IPv4 address with the given address fields and port number.

- .v4_mapped_v6(x0 : Int, x1 : Int, x2 : Int, x3 : Int, *, port : Int) : self

  Returns the IPv4-mapped IPv6 address `[::ffff:x0.x1.x2.x3]:port`.

- .v4_mapped_v6(fields : StaticArray(UInt8, 4), port : UInt16) : self

  Returns the IPv4-mapped IPv6 address with the given IPv4 address fields and port number.

- .v6(x0 : Int, x1 : Int, x2 : Int, x3 : Int, x4 : Int, x5 : Int, x6 : Int, x7 : Int, *, port : Int, zone_id : Int32 = 0) : self

  Returns the IPv6 address `[x0:x1:x2:x3:x4:x5:x6:x7]:port`.

- .v6(fields : StaticArray(UInt16, 8), port : UInt16, zone_id : Int32 = 0) : self

  Returns the IPv6 address with the given address fields, port number and scope identifier.

##
Class Method Summary

- .parse_v4_fields?(str : String) : StaticArray(UInt8, 4) | Nil

  Parses str as an IPv4 address and returns its fields, or returns `nil` if str does not contain a valid IPv4 address.

- .parse_v6_fields?(str : String) : StaticArray(UInt16, 8) | Nil

  Parses str as an IPv6 address and returns its fields, or returns `nil` if str does not contain a valid IPv6 address.

- .valid?(address : String) : Bool

  Returns `true` if address is a valid IPv4 or IPv6 address.

- .valid_port?(port : Int) : Bool

  Returns `true` if port is a valid port number.

- .valid_v4?(address : String) : Bool

  Returns `true` if address is a valid IPv4 address.

- .valid_v6?(address : String) : Bool

  Returns `true` if address is a valid IPv6 address.

##
Instance Method Summary

- #==(other : self)
- #address : String

  Returns a `String` representation of the IP address, without the port number.

- #hash(hasher)

  See `Object#hash(hasher)`

- #inspect(io : IO) : Nil

  Appends this struct's name and instance variables names and values to the given IO.

- #inspect : String

  Returns an unambiguous and information-rich string representation of this object, typically intended for developers.

- #link_local?

  Returns `true` if this IP is a link-local address.

- #link_local_interface : String | Nil

  Returns the interface name for a scoped/zoned link-local IPv6 address.

- #loopback? : Bool

  Returns `true` if this IP is a loopback address.

- #port : Int32
- #pretty_print(pp)
- #private? : Bool

  Returns `true` if this IP is a private address.

- #to_s(io : IO) : Nil

  Writes the `String` representation of the IP address plus the port number to the given io.

- #to_s : String

  Returns a `String` representation of the IP address plus the port number.

- #to_unsafe : Pointer(LibC::Sockaddr)
- #unspecified? : Bool

  Returns `true` if this IP is an unspecified address, either the IPv4 address `0.0.0.0` or the IPv6 address `::`.

- #zone_id : Int32

### Instance methods inherited from struct `Socket::Address`

family : Family family, size : Int32 size, to_unsafe : Pointer(LibC::Sockaddr) to_unsafe

### Constructor methods inherited from struct `Socket::Address`

from(sockaddr : Pointer(LibC::Sockaddr), addrlen) : Address
from(sockaddr : Pointer(LibC::Sockaddr)) : Address from, new(family : Family, size : Int32) new, parse(uri : URI) : self
parse(uri : String) : self parse

### Instance methods inherited from struct `Struct`

==(other : YAML::Any)
==(other) : Bool ==, hash(hasher) hash, inspect(io : IO) : Nil inspect, pretty_print(pp) : Nil pretty_print, to_s(io : IO) : Nil to_s

### Class methods inherited from struct `Struct`

pre_initialize(address : Pointer) : Nil pre_initialize

### Instance methods inherited from struct `Value`

==(other : Log::Metadata::Value)
==(other : JSON::Any)
==(other : YAML::Any)
==(other) ==, dup dup

### Instance methods inherited from class `Object`

! : Bool !, !=(other) !=, !~(other) !~, ==(other) ==, ===(other : JSON::Any)
===(other : YAML::Any)
===(other) ===, =~(other) =~, as(type : Class) as, as?(type : Class) as?, class class, dup dup, hash(hasher)
hash hash, in?(collection : Object) : Bool
in?(*values : Object) : Bool in?, inspect(io : IO) : Nil
inspect : String inspect, is_a?(type : Class) : Bool is_a?, itself itself, nil? : Bool nil?, not_nil!(message)
not_nil! not_nil!, pretty_inspect(width = 79, newline = "\n", indent = 0) : String pretty_inspect, pretty_print(pp : PrettyPrint) : Nil pretty_print, responds_to?(name : Symbol) : Bool responds_to?, tap(&) tap, to_json(io : IO) : Nil
to_json : String to_json, to_pretty_json(indent : String = " ") : String
to_pretty_json(io : IO, indent : String = " ") : Nil to_pretty_json, to_s(io : IO) : Nil
to_s : String to_s, to_yaml(io : IO) : Nil
to_yaml : String to_yaml, try(&) try, unsafe_as(type : T.class) forall T unsafe_as

### Class methods inherited from class `Object`

from_json(string_or_io : String | IO, root : String)
from_json(string_or_io : String | IO) from_json, from_yaml(string_or_io : String | IO) from_yaml

### Macros inherited from class `Object`

class_getter(*names, &block) class_getter, class_getter!(*names) class_getter!, class_getter?(*names, &block) class_getter?, class_property(*names, &block) class_property, class_property!(*names) class_property!, class_property?(*names, &block) class_property?, class_setter(*names) class_setter, def_clone def_clone, def_equals(*fields) def_equals, def_equals_and_hash(*fields) def_equals_and_hash, def_hash(*fields) def_hash, delegate(*methods, to object) delegate, forward_missing_to(delegate) forward_missing_to, getter(*names, &block) getter, getter!(*names) getter!, getter?(*names, &block) getter?, property(*names, &block) property, property!(*names) property!, property?(*names, &block) property?, setter(*names) setter

##
Constructor Detail

def self.from(sockaddr : Pointer(LibC::Sockaddr), addrlen) : IPAddress #

Creates an `IPAddress` from the internal OS representation. Supports both INET and INET6 families.

def self.from(sockaddr : Pointer(LibC::Sockaddr)) : IPAddress #

Creates an `IPAddress` from the internal OS representation. Supports both INET and INET6 families.

def self.new(address : String, port : Int32) #

Creates an `IPAddress` from the given IPv4 or IPv6 address and port number.

address is parsed using `.parse_v4_fields?` and `.parse_v6_fields?`. Raises `Socket::Error` if address does not contain a valid IP address or the port number is out of range.

Scoped/Zoned IPv6 link-local addresses are supported per RFC4007, e.g. `fe80::abcd%eth0` but will always use their numerical interface index in the `#inspect` representation. The interface name can be retrieved later using `#link_local_interface` on the `IPAddress` object.

    require "socket"

    Socket::IPAddress.new("127.0.0.1", 8080)                 # => Socket::IPAddress(127.0.0.1:8080)
    Socket::IPAddress.new("fe80::2ab2:bdff:fe59:8e2c", 1234) # => Socket::IPAddress([fe80::2ab2:bdff:fe59:8e2c]:1234)
    Socket::IPAddress.new("fe80::4567:8:9%eth0", 443)        # => Socket::IPAddress([fe80::4567:8:9%2]:443)

def self.parse(uri : URI) : IPAddress #

Parses a `Socket::IPAddress` from an URI.

It expects the URI to include `<scheme>://<host>:<port>` where `scheme` as well as any additional URI components (such as `path` or `query`) are ignored.

`host` must be an IP address (v4 or v6), otherwise `Socket::Error` will be raised. Domain names will not be resolved.

    require "socket"

    Socket::IPAddress.parse("tcp://127.0.0.1:8080") # => Socket::IPAddress.new("127.0.0.1", 8080)
    Socket::IPAddress.parse("udp://[::1]:8080")     # => Socket::IPAddress.new("::1", 8080)

def self.parse(uri : String) : self #

Parses a `Socket::IPAddress` from an URI.

It expects the URI to include `<scheme>://<host>:<port>` where `scheme` as well as any additional URI components (such as `path` or `query`) are ignored.

`host` must be an IP address (v4 or v6), otherwise `Socket::Error` will be raised. Domain names will not be resolved.

    require "socket"

    Socket::IPAddress.parse("tcp://127.0.0.1:8080") # => Socket::IPAddress.new("127.0.0.1", 8080)
    Socket::IPAddress.parse("udp://[::1]:8080")     # => Socket::IPAddress.new("::1", 8080)

def self.v4(x0 : Int, x1 : Int, x2 : Int, x3 : Int, *, port : Int) : self #

Returns the IPv4 address `x0.x1.x2.x3:port`.

Raises `Socket::Error` if any field or the port number is out of range.

def self.v4(fields : StaticArray(UInt8, 4), port : UInt16) : self #

Returns the IPv4 address with the given address fields and port number.

def self.v4_mapped_v6(x0 : Int, x1 : Int, x2 : Int, x3 : Int, *, port : Int) : self #

Returns the IPv4-mapped IPv6 address `[::ffff:x0.x1.x2.x3]:port`.

Raises `Socket::Error` if any field or the port number is out of range.

def self.v4_mapped_v6(fields : StaticArray(UInt8, 4), port : UInt16) : self #

Returns the IPv4-mapped IPv6 address with the given IPv4 address fields and port number.

def self.v6(x0 : Int, x1 : Int, x2 : Int, x3 : Int, x4 : Int, x5 : Int, x6 : Int, x7 : Int, *, port : Int, zone_id : Int32 = 0) : self #

Returns the IPv6 address `[x0:x1:x2:x3:x4:x5:x6:x7]:port`.

Raises `Socket::Error` if any field or the port number is out of range.

def self.v6(fields : StaticArray(UInt16, 8), port : UInt16, zone_id : Int32 = 0) : self #

Returns the IPv6 address with the given address fields, port number and scope identifier.

##
Class Method Detail

def self.parse_v4_fields?(str : String) : StaticArray(UInt8, 4) | Nil #

Parses str as an IPv4 address and returns its fields, or returns `nil` if str does not contain a valid IPv4 address.

The format of IPv4 addresses follows RFC 3493, section 6.3. No extensions (e.g. octal fields, fewer than 4 fields) are supported.

    require "socket"

    Socket::IPAddress.parse_v4_fields?("192.168.0.1")     # => UInt8.static_array(192, 168, 0, 1)
    Socket::IPAddress.parse_v4_fields?("255.255.255.254") # => UInt8.static_array(255, 255, 255, 254)
    Socket::IPAddress.parse_v4_fields?("01.2.3.4")        # => nil

def self.parse_v6_fields?(str : String) : StaticArray(UInt16, 8) | Nil #

Parses str as an IPv6 address and returns its fields, or returns `nil` if str does not contain a valid IPv6 address.

The format of IPv6 addresses follows RFC 4291, section 2.2. Both canonical and non-canonical forms are supported.

    require "socket"

    Socket::IPAddress.parse_v6_fields?("::1")                 # => UInt16.static_array(0, 0, 0, 0, 0, 0, 0, 1)
    Socket::IPAddress.parse_v6_fields?("a:0b:00c:000d:E:F::") # => UInt16.static_array(10, 11, 12, 13, 14, 15, 0, 0)
    Socket::IPAddress.parse_v6_fields?("::ffff:192.168.1.1")  # => UInt16.static_array(0, 0, 0, 0, 0, 0xffff, 0xc0a8, 0x0101)
    Socket::IPAddress.parse_v6_fields?("1::2::")              # => nil
    Socket::IPAddress.parse_v6_fields?("fe80::a:b%eth0")      # => StaticArray[65152, 0, 0, 0, 0, 0, 10, 11]

def self.valid?(address : String) : Bool #

Returns `true` if address is a valid IPv4 or IPv6 address.

def self.valid_port?(port : Int) : Bool #

Returns `true` if port is a valid port number.

Valid port numbers are in the range `0..65_535`.

def self.valid_v4?(address : String) : Bool #

Returns `true` if address is a valid IPv4 address.

def self.valid_v6?(address : String) : Bool #

Returns `true` if address is a valid IPv6 address.

##
Instance Method Detail

def ==(other : self) #
def address : String #

Returns a `String` representation of the IP address, without the port number.

IPv6 addresses are canonicalized according to RFC 5952, section 4. IPv4-mapped IPv6 addresses use the mixed notation according to RFC 5952, section 5.

    require "socket"

    v4 = Socket::IPAddress.v4(UInt8.static_array(127, 0, 0, 1), 8080)
    v4.address # => "127.0.0.1"

    v6 = Socket::IPAddress.v6(UInt16.static_array(0x2001, 0xdb8, 0, 0, 1, 0, 0, 1), 443)
    v6.address # => "2001:db8::1:0:0:1"

    mapped = Socket::IPAddress.v4_mapped_v6(UInt8.static_array(192, 168, 1, 15), 55001)
    mapped.address # => "::ffff:192.168.1.15"

To obtain both the address and the port number in one string, see `#to_s`.

def hash(hasher) #
Description copied from struct Struct

See `Object#hash(hasher)`

def inspect(io : IO) : Nil #
Description copied from struct Struct

Appends this struct's name and instance variables names and values to the given IO.

    struct Point
      def initialize(@x : Int32, @y : Int32)
      end
    end

    p1 = Point.new 1, 2
    p1.to_s    # "Point(@x=1, @y=2)"
    p1.inspect # "Point(@x=1, @y=2)"

def inspect : String #
Description copied from class Object

Returns an unambiguous and information-rich string representation of this object, typically intended for developers.

This method should usually not be overridden. It delegates to `#inspect(IO)` which can be overridden for custom implementations.

Also see `#to_s`.

def link_local? #

Returns `true` if this IP is a link-local address.

IPv4 addresses in `169.254.0.0/16` reserved by RFC 3927 and Link-Local IPv6 Unicast Addresses in `fe80::/10` reserved by RFC 4291 are considered link-local.

def link_local_interface : String | Nil #

Returns the interface name for a scoped/zoned link-local IPv6 address. This only works on properly initialized link-local IPv6 address objects. In any other case this will return nil.

The OS tracks the zone via a numerical interface index as enumerated by the kernel. To keep our abstraction class in line, we also only keep the interface index around.

This helper method exists to look up the interface name based on the associated zone_id property.

def loopback? : Bool #

Returns `true` if this IP is a loopback address.

In the IPv4 family, loopback addresses are all addresses in the subnet `127.0.0.0/24`. In IPv6 `::1` is the loopback address.

def port : Int32 #
def pretty_print(pp) #
def private? : Bool #

Returns `true` if this IP is a private address.

IPv4 addresses in `10.0.0.0/8`, `172.16.0.0/12` and `192.168.0.0/16` as defined in RFC 1918 and IPv6 Unique Local Addresses in `fc00::/7` as defined in RFC 4193 are considered private.

def to_s(io : IO) : Nil #

Writes the `String` representation of the IP address plus the port number to the given io.

IPv6 addresses are canonicalized according to RFC 5952, section 4, and surrounded within a pair of square brackets according to RFC 3986. IPv4-mapped IPv6 addresses use the mixed notation according to RFC 5952, section 5.

To obtain the address alone without the port number, see `#address`.

def to_s : String #

Returns a `String` representation of the IP address plus the port number.

IPv6 addresses are canonicalized according to RFC 5952, section 4, and surrounded within a pair of square brackets according to RFC 3986. IPv4-mapped IPv6 addresses use the mixed notation according to RFC 5952, section 5.

    require "socket"

    v4 = Socket::IPAddress.v4(UInt8.static_array(127, 0, 0, 1), 8080)
    v4.to_s # => "127.0.0.1:8080"

    v6 = Socket::IPAddress.v6(UInt16.static_array(0x2001, 0xdb8, 0, 0, 1, 0, 0, 1), 443)
    v6.to_s # => "[2001:db8::1:0:0:1]:443"

    mapped = Socket::IPAddress.v4_mapped_v6(UInt8.static_array(192, 168, 1, 15), 55001)
    mapped.to_s # => "[::ffff:192.168.1.15]:55001"

To obtain the address alone without the port number, see `#address`.

def to_unsafe : Pointer(LibC::Sockaddr) #
def unspecified? : Bool #

Returns `true` if this IP is an unspecified address, either the IPv4 address `0.0.0.0` or the IPv6 address `::`.

def zone_id : Int32 #