1 // Copyright (C) 2010-2020 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #ifndef IO_ADDRESS_H
8 #define IO_ADDRESS_H 1
9 
10 // IMPORTANT NOTE: only very few ASIO headers files can be included in
11 // this file.  In particular, asio.hpp should never be included here.
12 // See the description of the namespace below.
13 #include <unistd.h>             // for some network system calls
14 #include <stdint.h>             // for uint32_t
15 #include <boost/asio/ip/address.hpp>
16 
17 #include <functional>
18 #include <string>
19 #include <vector>
20 
21 #include <exceptions/exceptions.h>
22 
23 namespace isc {
24 namespace asiolink {
25 
26     /// Defines length of IPv6 address (in binary format).
27     static constexpr size_t V6ADDRESS_LEN = 16;
28 
29     /// Defines length of IPv4 address (in binary format).
30     static constexpr size_t V4ADDRESS_LEN = 4;
31 
32     /// @brief Maximum size of an IPv4 address represented as a text string. 12
33     ///     digits plus 3 full stops (dots).
34     static constexpr size_t V4ADDRESS_TEXT_MAX_LEN = 15u;
35 
36     /// @brief Maximum size of an IPv6 address represented as a text string. 32
37     ///     hexadecimal characters written in 8 groups of four, plus 7 colon
38     ///     separators.
39     static constexpr size_t V6ADDRESS_TEXT_MAX_LEN = 39u;
40 
41 /// \brief The \c IOAddress class represents an IP addresses (version
42 /// agnostic)
43 ///
44 /// This class is a wrapper for the ASIO \c ip::address class.
45 class IOAddress {
46 public:
47     ///
48     /// \name Constructors and Destructor
49     ///
50     /// This class is copyable.  We use default versions of copy constructor
51     /// and the assignment operator.
52     /// We use the default destructor.
53     //@{
54     /// \brief Constructor from string.
55     ///
56     /// This constructor converts a textual representation of IPv4 and IPv6
57     /// addresses into an IOAddress object.
58     /// If \c address_str is not a valid representation of any type of
59     /// address, an exception of class \c IOError will be thrown.
60     /// This constructor allocates memory for the object, and if that fails
61     /// a corresponding standard exception will be thrown.
62     ///
63     /// \param address_str Textual representation of address.
64     IOAddress(const std::string& address_str);
65 
66     /// \brief Constructor from an ASIO \c ip::address object.
67     ///
68     /// This constructor is intended to be used within the wrapper
69     /// implementation; user applications of the wrapper API won't use it.
70     ///
71     /// This constructor never throws an exception.
72     ///
73     /// \param asio_address The ASIO \c ip::address to be converted.
74     IOAddress(const boost::asio::ip::address& asio_address);
75     //@}
76 
77     /// @brief Constructor for ip::address_v4 object.
78     ///
79     /// This constructor is intended to be used when constructing
80     /// IPv4 address out of uint32_t type. Passed value must be in
81     /// network byte order
82     ///
83     /// @param v4address IPv4 address represented by uint32_t
84     IOAddress(uint32_t v4address);
85 
86     /// \brief Convert the address to a string.
87     ///
88     /// This method is basically expected to be exception free, but
89     /// generating the string will involve resource allocation,
90     /// and if it fails the corresponding standard exception will be thrown.
91     ///
92     /// \return A string representation of the address.
93     std::string toText() const;
94 
95     /// \brief Returns the address family
96     ///
97     /// \return AF_INET for IPv4 or AF_INET6 for IPv6.
98     short getFamily() const;
99 
100     /// \brief Convenience function to check for an IPv4 address
101     ///
102     /// \return true if the address is a V4 address
isV4()103     bool isV4() const {
104         return (asio_address_.is_v4());
105     }
106 
107     /// \brief Convenience function to check if it is an IPv4 zero address.
108     ///
109     /// \return true if the address is the zero IPv4 address.
isV4Zero()110     bool isV4Zero() const {
111         return (equals(IPV4_ZERO_ADDRESS()));
112     }
113 
114     /// \brief Convenience function to check if it is an IPv4 broadcast
115     ///        address.
116     ///
117     /// \return true if the address is the broadcast IPv4 address.
isV4Bcast()118     bool isV4Bcast() const {
119         return (equals(IPV4_BCAST_ADDRESS()));
120     }
121 
122     /// \brief Convenience function to check for an IPv6 address
123     ///
124     /// \return true if the address is a V6 address
isV6()125     bool isV6() const {
126         return (asio_address_.is_v6());
127     }
128 
129     /// \brief Convenience function to check if it is an IPv4 zero address.
130     ///
131     /// \return true if the address is the zero IPv4 address.
isV6Zero()132     bool isV6Zero() const {
133         return (equals(IPV6_ZERO_ADDRESS()));
134     }
135 
136     /// \brief checks whether and address is IPv6 and is link-local
137     ///
138     /// \return true if the address is IPv6 link-local, false otherwise
139     bool isV6LinkLocal() const;
140 
141     /// \brief checks whether and address is IPv6 and is multicast
142     ///
143     /// \return true if the address is IPv6 multicast, false otherwise
144     bool isV6Multicast() const;
145 
146     /// \brief Creates an address from over wire data.
147     ///
148     /// \param family AF_INET for IPv4 or AF_INET6 for IPv6.
149     /// \param data pointer to first char of data
150     ///
151     /// \return Created IOAddress object
152     static IOAddress fromBytes(short family, const uint8_t* data);
153 
154     /// \brief Return address as set of bytes
155     ///
156     /// \return Contents of the address as a set of bytes in network-byte
157     ///         order.
158     std::vector<uint8_t> toBytes() const;
159 
160     /// \brief Compare addresses for equality
161     ///
162     /// \param other Address to compare against.
163     ///
164     /// \return true if addresses are equal, false if not.
equals(const IOAddress & other)165     bool equals(const IOAddress& other) const {
166         return (asio_address_ == other.asio_address_);
167     }
168 
169     /// \brief Compare addresses for equality
170     ///
171     /// \param other Address to compare against.
172     ///
173     /// \return true if addresses are equal, false if not.
174     bool operator==(const IOAddress& other) const {
175         return equals(other);
176     }
177 
178     /// \brief Compare addresses for inequality
179     ///
180     /// \param other Address to compare against.
181     ///
182     /// \return false if addresses are equal, true if not.
nequals(const IOAddress & other)183     bool nequals(const IOAddress& other) const {
184         return (!equals(other));
185     }
186 
187     /// \brief Checks if one address is smaller than the other
188     ///
189     /// \param other Address to compare against.
190     bool operator<(const IOAddress& other) const {
191         return (asio_address_ < other.asio_address_);
192     }
193 
194     /// \brief Checks if one address is smaller or equal than the other
195     ///
196     /// \param other Address to compare against.
197     bool operator<=(const IOAddress& other) const {
198         return (asio_address_ <= other.asio_address_);
199     }
200 
201     /// \brief Compare addresses for inequality
202     ///
203     /// \param other Address to compare against.
204     ///
205     /// \return false if addresses are equal, true if not.
206     bool operator!=(const IOAddress& other) const {
207         return (nequals(other));
208     }
209 
210     /// @brief Subtracts one address from another (a - b)
211     ///
212     /// Treats addresses as integers and subtracts them. For example:
213     /// @code
214     /// 192.0.2.5 - 192.0.2.0 = 0.0.0.5
215     /// fe80::abcd - fe80:: = ::abcd
216     /// @endcode
217     ///
218     /// It is possible to subtract greater from lesser address, e.g.
219     /// 192.168.56.10 - 192.168.67.20, but please do understand that
220     /// the address space is a finite field in mathematical sense, so
221     /// you may end up with a result that is greater then any of the
222     /// addresses you specified. Also, subtraction is not commutative,
223     /// so a - b != b - a.
224     ///
225     /// This operation is essential for calculating the number of
226     /// leases in a pool, where we need to calculate (max - min).
227     /// @throw BadValue if addresses are of different family
228     /// @param a address to be subtracted from
229     /// @param b address to be subtracted
230     /// @return IOAddress object that represents the difference
231     static IOAddress subtract(const IOAddress& a, const IOAddress& b);
232 
233     /// @brief Returns an address increased by one
234     ///
235     /// This method works for both IPv4 and IPv6 addresses. For example,
236     /// increase 192.0.2.255 will become 192.0.3.0.
237     ///
238     /// Address space is a finite field in the mathematical sense, so keep
239     /// in mind that the address space "loops". 255.255.255.255 increased
240     /// by one gives 0.0.0.0. The same is true for maximum value of IPv6
241     /// (all 1's) looping to ::.
242     ///
243     /// @todo Determine if we have a use-case for increasing the address
244     /// by more than one. Increase by one is used in AllocEngine. This method
245     /// could take extra parameter that specifies the value by which the
246     /// address should be increased.
247     ///
248     /// @param addr address to be increased
249     /// @return address increased by one
250     static IOAddress
251     increase(const IOAddress& addr);
252 
253     /// \brief Converts IPv4 address to uint32_t
254     ///
255     /// Will throw BadValue exception if that is not IPv4
256     /// address.
257     ///
258     /// \return uint32_t that represents IPv4 address in
259     ///         network byte order
260     uint32_t toUint32() const;
261 
262     /// @name Methods returning @c IOAddress objects encapsulating typical addresses.
263     ///
264     //@{
265     /// @brief Returns an address set to all zeros.
IPV4_ZERO_ADDRESS()266     static const IOAddress& IPV4_ZERO_ADDRESS() {
267         static IOAddress address(0);
268         return (address);
269     }
270 
271     /// @brief Returns a "255.255.255.255" broadcast address.
IPV4_BCAST_ADDRESS()272     static const IOAddress& IPV4_BCAST_ADDRESS() {
273         static IOAddress address(0xFFFFFFFF);
274         return (address);
275     }
276 
277     /// @brief Returns an IPv6 zero address.
IPV6_ZERO_ADDRESS()278     static const IOAddress& IPV6_ZERO_ADDRESS() {
279         static IOAddress address("::");
280         return (address);
281     }
282 
283     //@}
284 
285 private:
286     boost::asio::ip::address asio_address_;
287 };
288 
289 /// \brief Insert the IOAddress as a string into stream.
290 ///
291 /// This method converts the \c address into a string and inserts it
292 /// into the output stream \c os.
293 ///
294 /// This function overloads the global operator<< to behave as described
295 /// in ostream::operator<< but applied to \c IOAddress objects.
296 ///
297 /// \param os A \c std::ostream object on which the insertion operation is
298 /// performed.
299 /// \param address The \c IOAddress object output by the operation.
300 /// \return A reference to the same \c std::ostream object referenced by
301 /// parameter \c os after the insertion operation.
302 std::ostream&
303 operator<<(std::ostream& os, const IOAddress& address);
304 
305 /// \brief Hash the IOAddress.
306 ///
307 /// This method allows boost multi-index hashed indexes on IOAddresses.
308 /// It follows the requirement with equality: if two addresses are equal
309 /// their hashes are equal, if two addresses are not equal their hashes
310 /// are almost surely not equal.
311 ///
312 /// \param address A \c IOAddress to hash.
313 /// \return The hash of the IOAddress.
314 size_t hash_value(const IOAddress& address);
315 
316 } // namespace asiolink
317 } // namespace isc
318 #endif // IO_ADDRESS_H
319