summaryrefslogtreecommitdiffstats
path: root/src/lib/asiolink/io_address.h
blob: d08753b5cfab795cbf0c7cf22db9dbc6c573eb85 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
// Copyright (C) 2010-2023 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef IO_ADDRESS_H
#define IO_ADDRESS_H 1

// IMPORTANT NOTE: only very few ASIO headers files can be included in
// this file.  In particular, asio.hpp should never be included here.
// See the description of the namespace below.
#include <unistd.h>             // for some network system calls
#include <stdint.h>             // for uint32_t
#include <boost/asio/ip/address.hpp>

#include <functional>
#include <string>
#include <vector>

#include <exceptions/exceptions.h>

namespace isc {
namespace asiolink {

    /// Defines length of IPv6 address (in binary format).
    static constexpr size_t V6ADDRESS_LEN = 16;

    /// Defines length of IPv4 address (in binary format).
    static constexpr size_t V4ADDRESS_LEN = 4;

    /// @brief Maximum size of an IPv4 address represented as a text string. 12
    ///     digits plus 3 full stops (dots).
    static constexpr size_t V4ADDRESS_TEXT_MAX_LEN = 15u;

    /// @brief Maximum size of an IPv6 address represented as a text string. 32
    ///     hexadecimal characters written in 8 groups of four, plus 7 colon
    ///     separators.
    static constexpr size_t V6ADDRESS_TEXT_MAX_LEN = 39u;

/// \brief The \c IOAddress class represents an IP addresses (version
/// agnostic)
///
/// This class is a wrapper for the ASIO \c ip::address class.
class IOAddress {
public:

    /// \brief An \c IOAddress hash enabling the use in the unordered
    /// STL containers.
    struct Hash {
        /// \brief A hashing operator.
        ///
        /// \param io_address an address to be hashed.
        /// \return a hashing result.
        size_t operator()(const IOAddress &io_address) const;
    };

    ///
    /// \name Constructors and Destructor
    ///
    /// This class is copyable.  We use default versions of copy constructor
    /// and the assignment operator.
    /// We use the default destructor.
    //@{
    /// \brief Constructor from string.
    ///
    /// This constructor converts a textual representation of IPv4 and IPv6
    /// addresses into an IOAddress object.
    /// If \c address_str is not a valid representation of any type of
    /// address, an exception of class \c IOError will be thrown.
    /// This constructor allocates memory for the object, and if that fails
    /// a corresponding standard exception will be thrown.
    ///
    /// \param address_str Textual representation of address.
    IOAddress(const std::string& address_str);

    /// \brief Constructor from an ASIO \c ip::address object.
    ///
    /// This constructor is intended to be used within the wrapper
    /// implementation; user applications of the wrapper API won't use it.
    ///
    /// This constructor never throws an exception.
    ///
    /// \param asio_address The ASIO \c ip::address to be converted.
    IOAddress(const boost::asio::ip::address& asio_address);
    //@}

    /// @brief Constructor for ip::address_v4 object.
    ///
    /// This constructor is intended to be used when constructing
    /// IPv4 address out of uint32_t type. Passed value must be in
    /// network byte order
    ///
    /// @param v4address IPv4 address represented by uint32_t
    IOAddress(uint32_t v4address);

    /// \brief Convert the address to a string.
    ///
    /// This method is basically expected to be exception free, but
    /// generating the string will involve resource allocation,
    /// and if it fails the corresponding standard exception will be thrown.
    ///
    /// \return A string representation of the address.
    std::string toText() const;

    /// \brief Returns the address family
    ///
    /// \return AF_INET for IPv4 or AF_INET6 for IPv6.
    short getFamily() const;

    /// \brief Convenience function to check for an IPv4 address
    ///
    /// \return true if the address is a V4 address
    bool isV4() const {
        return (asio_address_.is_v4());
    }

    /// \brief Convenience function to check if it is an IPv4 zero address.
    ///
    /// \return true if the address is the zero IPv4 address.
    bool isV4Zero() const {
        return (equals(IPV4_ZERO_ADDRESS()));
    }

    /// \brief Convenience function to check if it is an IPv4 broadcast
    ///        address.
    ///
    /// \return true if the address is the broadcast IPv4 address.
    bool isV4Bcast() const {
        return (equals(IPV4_BCAST_ADDRESS()));
    }

    /// \brief Convenience function to check for an IPv6 address
    ///
    /// \return true if the address is a V6 address
    bool isV6() const {
        return (asio_address_.is_v6());
    }

    /// \brief Convenience function to check if it is an IPv4 zero address.
    ///
    /// \return true if the address is the zero IPv4 address.
    bool isV6Zero() const {
        return (equals(IPV6_ZERO_ADDRESS()));
    }

    /// \brief checks whether and address is IPv6 and is link-local
    ///
    /// \return true if the address is IPv6 link-local, false otherwise
    bool isV6LinkLocal() const;

    /// \brief checks whether and address is IPv6 and is multicast
    ///
    /// \return true if the address is IPv6 multicast, false otherwise
    bool isV6Multicast() const;

    /// \brief Creates an address from over wire data.
    ///
    /// \param family AF_INET for IPv4 or AF_INET6 for IPv6.
    /// \param data pointer to first char of data
    ///
    /// \return Created IOAddress object
    static IOAddress fromBytes(short family, const uint8_t* data);

    /// \brief Return address as set of bytes
    ///
    /// \return Contents of the address as a set of bytes in network-byte
    ///         order.
    std::vector<uint8_t> toBytes() const;

    /// \brief Compare addresses for equality
    ///
    /// \param other Address to compare against.
    ///
    /// \return true if addresses are equal, false if not.
    bool equals(const IOAddress& other) const {
        return (asio_address_ == other.asio_address_);
    }

    /// \brief Compare addresses for equality
    ///
    /// \param other Address to compare against.
    ///
    /// \return true if addresses are equal, false if not.
    bool operator==(const IOAddress& other) const {
        return equals(other);
    }

    /// \brief Compare addresses for inequality
    ///
    /// \param other Address to compare against.
    ///
    /// \return false if addresses are equal, true if not.
    bool nequals(const IOAddress& other) const {
        return (!equals(other));
    }

    /// \brief Checks if one address is smaller than the other
    ///
    /// \param other Address to compare against.
    bool operator<(const IOAddress& other) const {
        return (asio_address_ < other.asio_address_);
    }

    /// \brief Checks if one address is smaller or equal than the other
    ///
    /// \param other Address to compare against.
    bool operator<=(const IOAddress& other) const {
        return (asio_address_ <= other.asio_address_);
    }

    /// \brief Compare addresses for inequality
    ///
    /// \param other Address to compare against.
    ///
    /// \return false if addresses are equal, true if not.
    bool operator!=(const IOAddress& other) const {
        return (nequals(other));
    }

    /// @brief Subtracts one address from another (a - b)
    ///
    /// Treats addresses as integers and subtracts them. For example:
    /// @code
    /// 192.0.2.5 - 192.0.2.0 = 0.0.0.5
    /// fe80::abcd - fe80:: = ::abcd
    /// @endcode
    ///
    /// It is possible to subtract greater from lesser address, e.g.
    /// 192.168.56.10 - 192.168.67.20, but please do understand that
    /// the address space is a finite field in mathematical sense, so
    /// you may end up with a result that is greater then any of the
    /// addresses you specified. Also, subtraction is not commutative,
    /// so a - b != b - a.
    ///
    /// This operation is essential for calculating the number of
    /// leases in a pool, where we need to calculate (max - min).
    /// @throw BadValue if addresses are of different family
    /// @param a address to be subtracted from
    /// @param b address to be subtracted
    /// @return IOAddress object that represents the difference
    static IOAddress subtract(const IOAddress& a, const IOAddress& b);

    /// @brief Returns an address increased by one
    ///
    /// This method works for both IPv4 and IPv6 addresses. For example,
    /// increase 192.0.2.255 will become 192.0.3.0.
    ///
    /// Address space is a finite field in the mathematical sense, so keep
    /// in mind that the address space "loops". 255.255.255.255 increased
    /// by one gives 0.0.0.0. The same is true for maximum value of IPv6
    /// (all 1's) looping to ::.
    ///
    /// @todo Determine if we have a use-case for increasing the address
    /// by more than one. Increase by one is used in AllocEngine. This method
    /// could take extra parameter that specifies the value by which the
    /// address should be increased.
    ///
    /// @param addr address to be increased
    /// @return address increased by one
    static IOAddress
    increase(const IOAddress& addr);

    /// \brief Converts IPv4 address to uint32_t
    ///
    /// Will throw BadValue exception if that is not IPv4
    /// address.
    ///
    /// \return uint32_t that represents IPv4 address in
    ///         network byte order
    uint32_t toUint32() const;

    /// @name Methods returning @c IOAddress objects encapsulating typical addresses.
    ///
    //@{
    /// @brief Returns an address set to all zeros.
    static const IOAddress& IPV4_ZERO_ADDRESS() {
        static IOAddress address(0);
        return (address);
    }

    /// @brief Returns a "255.255.255.255" broadcast address.
    static const IOAddress& IPV4_BCAST_ADDRESS() {
        static IOAddress address(0xFFFFFFFF);
        return (address);
    }

    /// @brief Returns an IPv6 zero address.
    static const IOAddress& IPV6_ZERO_ADDRESS() {
        static IOAddress address("::");
        return (address);
    }

    //@}

private:
    boost::asio::ip::address asio_address_;
};

/// \brief Insert the IOAddress as a string into stream.
///
/// This method converts the \c address into a string and inserts it
/// into the output stream \c os.
///
/// This function overloads the global operator<< to behave as described
/// in ostream::operator<< but applied to \c IOAddress objects.
///
/// \param os A \c std::ostream object on which the insertion operation is
/// performed.
/// \param address The \c IOAddress object output by the operation.
/// \return A reference to the same \c std::ostream object referenced by
/// parameter \c os after the insertion operation.
std::ostream&
operator<<(std::ostream& os, const IOAddress& address);

/// \brief Hash the IOAddress.
///
/// This method allows boost multi-index hashed indexes on IOAddresses.
/// It follows the requirement with equality: if two addresses are equal
/// their hashes are equal, if two addresses are not equal their hashes
/// are almost surely not equal.
///
/// \param address A \c IOAddress to hash.
/// \return The hash of the IOAddress.
size_t hash_value(const IOAddress& address);

} // namespace asiolink
} // namespace isc
#endif // IO_ADDRESS_H