Botan 3.13.0
Crypto and TLS for C&
ipv6_address.h
Go to the documentation of this file.
1/*
2* (C) 2026 Jack Lloyd
3*
4* Botan is released under the Simplified BSD License (see license.txt)
5*/
6
7#ifndef BOTAN_IPV6_ADDRESS_H_
8#define BOTAN_IPV6_ADDRESS_H_
9
10#include <botan/types.h>
11#include <array>
12#include <optional>
13#include <span>
14#include <string>
15#include <string_view>
16#include <vector>
17
18namespace Botan {
19
20class IPv4Address;
21
22/**
23* IPv6 Address
24*/
25class BOTAN_PUBLIC_API(3, 12) IPv6Address final {
26 public:
27 /**
28 * Create an address from its 16 byte big-endian encoding
29 * @param ip the bytes of the address
30 */
31 explicit IPv6Address(std::span<const uint8_t, 16> ip);
32
33 /**
34 * Create an address from its 16 byte big-endian encoding
35 * @param ip the bytes of the address
36 */
37 explicit IPv6Address(std::array<uint8_t, 16> ip) : m_ip(ip) {}
38
39 /**
40 * Convert a string representation of an IPv6 address to IPv6Address.
41 *
42 * Accepts the full form (eight colon-separated hex groups), the
43 * "::"-compressed form (exactly one run of zero groups elided), and
44 * combinations such as "2001:db8::1". The final 32 bits may be given
45 * in IPv4 dotted-decimal form (e.g. "::ffff:192.0.2.1"). Surrounding
46 * brackets and zone identifiers are not accepted.
47 */
48 static std::optional<IPv6Address> from_string(std::string_view str);
49
50 /**
51 * Return an address with the leading @p bits set to one and the remainder
52 * zero. Throws Invalid_Argument if @p bits > 128.
53 */
54 static IPv6Address netmask(size_t bits);
55
56 /**
57 * Return the netmask matching a single host
58 * @return an address with all 128 bits set
59 */
60 static IPv6Address host_mask() { return netmask(128); }
61
62 /**
63 * Bitwise AND of two addresses, typically used to apply a netmask
64 * @param other the address to AND with
65 * @return the bitwise AND of the two addresses
66 */
67 IPv6Address operator&(const IPv6Address& other) const;
68
69 /**
70 * Order two addresses numerically
71 * @return the ordering of this address relative to the other
72 */
73 auto operator<=>(const IPv6Address&) const = default;
74
75 /**
76 * Access the raw bytes of the address
77 * @return the 16 byte big-endian encoding of the address
78 */
79 std::array<uint8_t, 16> address() const { return m_ip; }
80
81 /**
82 * Convert an IPv6 address to the RFC 5952 canonical text form:
83 * lowercase hex, leading zeros within a group suppressed, and the
84 * longest run of two or more zero groups compressed to "::". The
85 * mixed hex/dotted notation is never produced, even for IPv4-mapped
86 * addresses.
87 */
88 std::string to_string() const;
89
90 /**
91 * If this value is a netmask consisting of a run of one bits followed by
92 * a run of zero bits, return the number of one bits.
93 *
94 * Otherwise return nullopt.
95 */
96 std::optional<size_t> prefix_length() const;
97
98 /**
99 * If this IPv6 address is an IPv4-compatible IPv6 address (RFC 4291 2.5.5.1)
100 * or an IPv4-mapped IPv6 address (RFC 4291 2.5.5.2), return the embedded
101 * IPv4 address.
102 */
103 std::optional<IPv4Address> as_ipv4() const;
104
105 private:
106 std::array<uint8_t, 16> m_ip;
107};
108
109/**
110* An IPv6 subnet in CIDR form: a network address paired with a prefix length
111*/
112class BOTAN_PUBLIC_API(3, 12) IPv6Subnet final {
113 public:
114 /**
115 * Construct from a network address and a prefix length in [0, 128].
116 * Host bits of @p address are cleared.
117 *
118 * Throws Invalid_Argument if @p prefix_length > 128.
119 */
121
122 /**
123 * Construct from a network address and a 16-byte CIDR netmask.
124 * Returns nullopt if netmask is not a valid contiguous CIDR prefix.
125 */
126 static std::optional<IPv6Subnet> from_address_and_mask(std::span<const uint8_t, 32> addr_and_mask);
127
128 /**
129 * Parse the CIDR-style form "2001:db8::/32".
130 *
131 * The "/N" suffix is required: bare addresses should be parsed via
132 * IPv6Address::from_string and wrapped with IPv6Subnet::host if needed.
133 * The input must already be canonical, such that from_string and
134 * to_string are exact inverses: the address is RFC 5952 form with host
135 * bits clear ("2001:db8::/32") and the prefix length is canonical
136 * decimal ("/32", not "/032"). In particular the IPv4-mapped dotted form
137 * ("::ffff:1.2.3.4/120") is rejected even though IPv6Address::from_string
138 * would accept the address.
139 *
140 * Returns nullopt on parse failure or out-of-range prefix length.
141 */
142 static std::optional<IPv6Subnet> from_string(std::string_view str);
143
144 /**
145 * A single-host subnet (prefix length 128) covering exactly @p address.
146 */
148
149 /// The network address (host bits already zeroed).
150 const IPv6Address& address() const { return m_address; }
151
152 /// Prefix length in [0, 128].
153 size_t prefix_length() const { return m_prefix_length; }
154
155 /// True iff prefix_length() == 128.
156 bool is_host() const { return m_prefix_length == 128; }
157
158 /// True iff @p ip falls within this subnet.
159 bool contains(const IPv6Address& ip) const;
160
161 /// CIDR-style "2001:db8::/32".
162 std::string to_string() const;
163
164 /**
165 * Bytes for use in a DER-encoded GeneralName iPAddress field:
166 * - 16 bytes (the address) if is_host(); the SAN form per RFC 5280 4.2.1.6.
167 * - 32 bytes (address || netmask) otherwise; the name constraint form
168 * per RFC 5280 4.2.1.10.
169 */
170 std::vector<uint8_t> serialize() const;
171
172 friend bool operator==(const IPv6Subnet&, const IPv6Subnet&) = default;
173
174 private:
175 IPv6Address m_address;
176 uint8_t m_prefix_length;
177};
178
179} // namespace Botan
180
181#endif
#define BOTAN_PUBLIC_API(maj, min)
Definition api.h:21
std::array< uint8_t, 16 > address() const
static IPv6Address host_mask()
auto operator<=>(const IPv6Address &) const =default
IPv6Address(std::span< const uint8_t, 16 > ip)
static IPv6Address netmask(size_t bits)
IPv6Address(std::array< uint8_t, 16 > ip)
friend bool operator==(const IPv6Subnet &, const IPv6Subnet &)=default
size_t prefix_length() const
Prefix length in [0, 128].
static std::optional< IPv6Subnet > from_address_and_mask(std::span< const uint8_t, 32 > addr_and_mask)
const IPv6Address & address() const
The network address (host bits already zeroed).
static std::optional< IPv6Subnet > from_string(std::string_view str)
IPv6Subnet(IPv6Address address, size_t prefix_length)
bool is_host() const
True iff prefix_length() == 128.
static IPv6Subnet host(IPv6Address address)
std::string to_string(ErrorType type)
Convert an ErrorType to string.
Definition exceptn.cpp:13
ECIES_Flags operator&(ECIES_Flags a, ECIES_Flags b)
Definition ecies.h:70