Kea 2.5.8
io_address.cc
Go to the documentation of this file.
1// Copyright (C) 2010-2024 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#include <config.h>
10#include <asiolink/io_error.h>
12
13#include <boost/static_assert.hpp>
14// moved to container_hash on recent boost versions (backward compatible)
15#include <boost/functional/hash.hpp>
16
17#include <unistd.h> // for some IPC/network system calls
18#include <stdint.h>
19#include <sys/socket.h>
20#include <netinet/in.h>
21
22using namespace boost::asio;
23using boost::asio::ip::udp;
24using boost::asio::ip::tcp;
25
26using namespace std;
27
28namespace isc {
29namespace asiolink {
30
31size_t
32IOAddress::Hash::operator()(const IOAddress &io_address) const {
33 return (hash_value(io_address));
34}
35
36// XXX: we cannot simply construct the address in the initialization list,
37// because we'd like to throw our own exception on failure.
38IOAddress::IOAddress(const std::string& address_str) {
39 boost::system::error_code err;
40 asio_address_ = ip::address::from_string(address_str, err);
41 if (err) {
42 isc_throw(IOError, "Failed to convert string to address '"
43 << address_str << "': " << err.message());
44 }
45}
46
47IOAddress::IOAddress(const boost::asio::ip::address& asio_address) :
48 asio_address_(asio_address)
49{}
50
51IOAddress::IOAddress(uint32_t v4address):
52 asio_address_(boost::asio::ip::address_v4(v4address)) {
53
54}
55
56string
58 return (asio_address_.to_string());
59}
60
62IOAddress::fromBytes(short family, const uint8_t* data) {
63 if (data == NULL) {
64 isc_throw(BadValue, "NULL pointer received.");
65 } else if ((family != AF_INET) && (family != AF_INET6)) {
66 isc_throw(BadValue, "Invalid family type. Only AF_INET and AF_INET6"
67 << "are supported");
68 }
69
70 BOOST_STATIC_ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
71 char addr_str[INET6_ADDRSTRLEN];
72 inet_ntop(family, data, addr_str, INET6_ADDRSTRLEN);
73 return IOAddress(string(addr_str));
74}
75
76std::vector<uint8_t>
78 if (asio_address_.is_v4()) {
79 const boost::asio::ip::address_v4::bytes_type bytes4 =
80 asio_address_.to_v4().to_bytes();
81 return (std::vector<uint8_t>(bytes4.begin(), bytes4.end()));
82 }
83
84 // Not V4 address, so must be a V6 address (else we could never construct
85 // this object).
86 const boost::asio::ip::address_v6::bytes_type bytes6 =
87 asio_address_.to_v6().to_bytes();
88 return (std::vector<uint8_t>(bytes6.begin(), bytes6.end()));
89}
90
91short
93 if (asio_address_.is_v4()) {
94 return (AF_INET);
95 } else {
96 return (AF_INET6);
97 }
98}
99
100bool
102 if (!asio_address_.is_v6()) {
103 return (false);
104 }
105 return (asio_address_.to_v6().is_link_local());
106}
107
108bool
110 if (!asio_address_.is_v6()) {
111 return (false);
112 }
113 return (asio_address_.to_v6().is_multicast());
114}
115
116uint32_t
118 if (asio_address_.is_v4()) {
119 return (asio_address_.to_v4().to_ulong());
120 } else {
121 isc_throw(BadValue, "Can't convert " << toText()
122 << " address to IPv4.");
123 }
124}
125
126std::ostream&
127operator<<(std::ostream& os, const IOAddress& address) {
128 os << address.toText();
129 return (os);
130}
131
132IOAddress
134 if (a.getFamily() != b.getFamily()) {
135 isc_throw(BadValue, "Both addresses have to be the same family");
136 }
137 if (a.isV4()) {
138 // Subtracting v4 is easy. We have a conversion function to uint32_t.
139 return (IOAddress(a.toUint32() - b.toUint32()));
140 } else {
141 // v6 is more involved.
142
143 // Let's extract the raw data first.
144 vector<uint8_t> a_vec = a.toBytes();
145 vector<uint8_t> b_vec = b.toBytes();
146
147 // ... and prepare the result
148 vector<uint8_t> result(V6ADDRESS_LEN,0);
149
150 // Carry is a boolean, but to avoid its frequent casting, let's
151 // use uint8_t. Also, some would prefer to call it borrow, but I prefer
152 // carry. Somewhat relevant discussion here:
153 // http://en.wikipedia.org/wiki/Carry_flag#Carry_flag_vs._Borrow_flag
154 uint8_t carry = 0;
155
156 // Now perform subtraction with borrow.
157 for (int i = a_vec.size() - 1; i >= 0; --i) {
158 result[i] = a_vec[i] - b_vec[i] - carry;
159 carry = (a_vec[i] < b_vec[i] + carry);
160 }
161
162 return (fromBytes(AF_INET6, &result[0]));
163 }
164}
165
168 std::vector<uint8_t> packed(addr.toBytes());
169
170 // Start increasing the least significant byte
171 for (int i = packed.size() - 1; i >= 0; --i) {
172 // if we haven't overflowed (0xff -> 0x0), than we are done
173 if (++packed[i] != 0) {
174 break;
175 }
176 }
177
178 return (IOAddress::fromBytes(addr.getFamily(), &packed[0]));
179}
180
181size_t
182hash_value(const IOAddress& address) {
183 if (address.isV4()) {
184 boost::hash<uint32_t> hasher;
185 return (hasher(address.toUint32()));
186 } else {
187 boost::hash<std::vector<uint8_t> > hasher;
188 return (hasher(address.toBytes()));
189 }
190}
191
192} // namespace asiolink
193} // namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Defines the logger used by the top-level component of kea-lfc.