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