Kea 2.5.5
io_address.cc
Go to the documentation of this file.
1// Copyright (C) 2010-2023 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
66 if ( (family != AF_INET) && (family != AF_INET6) ) {
67 isc_throw(BadValue, "Invalid family type. Only AF_INET and AF_INET6"
68 << "are supported");
69 }
70
71 BOOST_STATIC_ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
72 char addr_str[INET6_ADDRSTRLEN];
73 inet_ntop(family, data, addr_str, INET6_ADDRSTRLEN);
74 return IOAddress(string(addr_str));
75}
76
77std::vector<uint8_t>
79 if (asio_address_.is_v4()) {
80 const boost::asio::ip::address_v4::bytes_type bytes4 =
81 asio_address_.to_v4().to_bytes();
82 return (std::vector<uint8_t>(bytes4.begin(), bytes4.end()));
83 }
84
85 // Not V4 address, so must be a V6 address (else we could never construct
86 // this object).
87 const boost::asio::ip::address_v6::bytes_type bytes6 =
88 asio_address_.to_v6().to_bytes();
89 return (std::vector<uint8_t>(bytes6.begin(), bytes6.end()));
90}
91
92short
94 if (asio_address_.is_v4()) {
95 return (AF_INET);
96 } else {
97 return (AF_INET6);
98 }
99}
100
101bool
103 if (!asio_address_.is_v6()) {
104 return (false);
105 }
106 return (asio_address_.to_v6().is_link_local());
107}
108
109bool
111 if (!asio_address_.is_v6()) {
112 return (false);
113 }
114 return (asio_address_.to_v6().is_multicast());
115}
116
117uint32_t
119 if (asio_address_.is_v4()) {
120 return (asio_address_.to_v4().to_ulong());
121 } else {
122 isc_throw(BadValue, "Can't convert " << toText()
123 << " address to IPv4.");
124 }
125}
126
127std::ostream&
128operator<<(std::ostream& os, const IOAddress& address) {
129 os << address.toText();
130 return (os);
131}
132
133IOAddress
135 if (a.getFamily() != b.getFamily()) {
136 isc_throw(BadValue, "Both addresses have to be the same family");
137 }
138 if (a.isV4()) {
139 // Subtracting v4 is easy. We have a conversion function to uint32_t.
140 return (IOAddress(a.toUint32() - b.toUint32()));
141 } else {
142 // v6 is more involved.
143
144 // Let's extract the raw data first.
145 vector<uint8_t> a_vec = a.toBytes();
146 vector<uint8_t> b_vec = b.toBytes();
147
148 // ... and prepare the result
149 vector<uint8_t> result(V6ADDRESS_LEN,0);
150
151 // Carry is a boolean, but to avoid its frequent casting, let's
152 // use uint8_t. Also, some would prefer to call it borrow, but I prefer
153 // carry. Somewhat relevant discussion here:
154 // http://en.wikipedia.org/wiki/Carry_flag#Carry_flag_vs._Borrow_flag
155 uint8_t carry = 0;
156
157 // Now perform subtraction with borrow.
158 for (int i = a_vec.size() - 1; i >= 0; --i) {
159 result[i] = a_vec[i] - b_vec[i] - carry;
160 carry = (a_vec[i] < b_vec[i] + carry);
161 }
162
163 return (fromBytes(AF_INET6, &result[0]));
164 }
165}
166
169 std::vector<uint8_t> packed(addr.toBytes());
170
171 // Start increasing the least significant byte
172 for (int i = packed.size() - 1; i >= 0; --i) {
173 // if we haven't overflowed (0xff -> 0x0), than we are done
174 if (++packed[i] != 0) {
175 break;
176 }
177 }
178
179 return (IOAddress::fromBytes(addr.getFamily(), &packed[0]));
180}
181
182size_t
183hash_value(const IOAddress& address) {
184 if (address.isV4()) {
185 boost::hash<uint32_t> hasher;
186 return (hasher(address.toUint32()));
187 } else {
188 boost::hash<std::vector<uint8_t> > hasher;
189 return (hasher(address.toBytes()));
190 }
191}
192
193} // namespace asiolink
194} // 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.