.. _net-addresses: ***************** Network addresses ***************** .. highlight:: c :: #include IP addresses ------------ libcork provides C types for storing IPv4 and IPv6 addresses, as well as a union type for storing a generic IP address, regardless of whether it's IPv4 or IPv6. (This lets you distinguish between an IPv4 address and the equivalent ``::ffff:0:0/96`` IPv4-mapped IPv6 address.) .. type:: struct cork_ipv4 struct cork_ipv6 An IPv4 or IPv6 address. The address is stored in memory exactly as it would be if sent over a network connection — i.e., in network-endian order, regardless of the endianness of the current host. The types are also guaranteed to be exactly the size of an actual IPv4 or IPv6 address (without additional padding), so they can be embedded directly into ``struct`` types that represent binary disk/wire formats. The contents of these types should be considered opaque. You should use the accessor functions defined below to interact with the IP address. .. type:: struct cork_ip A single union type that can contain either an IPv4 or IPv6 address. This type contains a discriminator field, so you can't use it directly in a binary disk/wire format type. .. member:: unsigned int version Either ``4`` or ``6``, indicating whether the current IP address is an IPv4 address or an IPv6 address. .. member:: struct cork_ipv4 ip.v4 struct cork_ipv6 ip.v6 Gives you access to the underlying :c:type:`cork_ipv4` or :c:type:`cork_ipv6` instance for the current address. It's your responsibility to check the :c:member:`cork_ip.version` field and only access the union branch that corresponds to the current IP version. .. function:: void cork_ipv4_copy(struct cork_ipv4 \*addr, const void \*src) void cork_ipv6_copy(struct cork_ipv6 \*addr, const void \*src) void cork_ip_from_ipv4(struct cork_ip \*addr, const void \*src) void cork_ip_from_ipv6(struct cork_ip \*addr, const void \*src) Initializes a :c:type:`cork_ipv4`, :c:type:`cork_ipv6`, or :c:type:`cork_ip` instance from an existing IP address somewhere in memory. The existing address doesn't have to be an instance of the :c:type:`cork_ipv4` or :c:type:`cork_ipv6` types, but it does have to be a well-formed address. (For IPv4, it must be 4 bytes long; for IPv6, 16 bytes long. And in both cases, the address must already be in network-endian order, regardless of the host's endianness.) .. function:: int cork_ipv4_init(struct cork_ipv4 \*addr, const char \*str) int cork_ipv6_init(struct cork_ipv6 \*addr, const char \*str) int cork_ip_init(struct cork_ip \*addr, const char \*str) Initializes a :c:type:`cork_ipv4`, :c:type:`cork_ipv6`, or :c:type:`cork_ip` instance from the string representation of an IP address. *str* must point to a string containing a well-formed IP address. (Dotted-quad for an IPv4, and colon-hex for IPv6.) Moreover, the version of the IP address in *str* must be compatible with the function that you call: it can't be an IPv6 address if you call ``cork_ipv4_init``, and it can't be an IPv4 address if you call ``cork_ipv6_init``. If *str* doesn't represent a valid address (of a compatible IP version), then we leave *addr* unchanged, fill in the current error condition with a :c:data:`CORK_NET_ADDRESS_PARSE_ERROR` error, and return ``-1``. .. function:: bool cork_ipv4_equal(const struct cork_ipv4 \*addr1, const struct cork_ipv4 \*addr2) bool cork_ipv6_equal(const struct cork_ipv6 \*addr1, const struct cork_ipv6 \*addr2) bool cork_ip_equal(const struct cork_ip \*addr1, const struct cork_ip \*addr2) Checks two IP addresses for equality. .. macro:: CORK_IPV4_STRING_LENGTH CORK_IPV6_STRING_LENGTH CORK_IP_STRING_LENGTH The maximum length of the string representation of an IPv4, IPv6, or generic IP address, including a ``NUL`` terminator. .. function:: void cork_ipv4_to_raw_string(const struct cork_ipv4 \*addr, char \*dest) void cork_ipv6_to_raw_string(const struct cork_ipv6 \*addr, char \*dest) void cork_ip_to_raw_string(const struct cork_ip \*addr, char \*dest) Fills in *dest* with the string representation of an IPv4, IPv6, or generic IP address. You are responsible for ensuring that *dest* is large enough to hold the string representation of any valid IP address of the given version. The :c:macro:`CORK_IPV4_STRING_LENGTH`, :c:macro:`CORK_IPV6_STRING_LENGTH`, and :c:macro:`CORK_IP_STRING_LENGTH` macros can be helpful for this:: char buf[CORK_IPV4_STRING_LENGTH]; struct cork_ipv4 addr; cork_ipv4_to_raw_string(&addr, buf); .. function:: bool cork_ipv4_is_valid_network(const struct cork_ipv4 \*addr, unsigned int cidr_prefix) bool cork_ipv6_is_valid_network(const struct cork_ipv6 \*addr, unsigned int cidr_prefix) bool cork_ip_is_valid_network(const struct cork_ipv6 \*addr, unsigned int cidr_prefix) Checks an IP address for alignment with a CIDR block prefix. For example, 10.1.2.4/24 is invalid, but 10.1.2.4/30 is valid. .. macro:: CORK_NET_ADDRESS_ERROR CORK_NET_ADDRESS_PARSE_ERROR The error class and codes used for the :ref:`error conditions ` described in this section.