Kea 2.7.6
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
22#if BOOST_VERSION < 106600
23#error "Boost ASIO older than 1.66 are not supported"
24#endif
25
26using namespace boost::asio;
27using boost::asio::ip::udp;
28using boost::asio::ip::tcp;
29
30using namespace std;
31
32namespace isc {
33namespace asiolink {
34
35size_t
36IOAddress::Hash::operator()(const IOAddress &io_address) const {
37 return (hash_value(io_address));
38}
39
40// XXX: we cannot simply construct the address in the initialization list,
41// because we'd like to throw our own exception on failure.
42IOAddress::IOAddress(const std::string& address_str) {
43 boost::system::error_code err;
44 asio_address_ = ip::make_address(address_str, err);
45 if (err) {
46 isc_throw(IOError, "Failed to convert string to address '"
47 << address_str << "': " << err.message());
48 }
49}
50
51IOAddress::IOAddress(const boost::asio::ip::address& asio_address) :
52 asio_address_(asio_address)
53{}
54
55IOAddress::IOAddress(uint32_t v4address):
56 asio_address_(boost::asio::ip::address_v4(v4address)) {
57
58}
59
60string
62 return (asio_address_.to_string());
63}
64
66IOAddress::fromBytes(short family, const uint8_t* data) {
67 if (data == NULL) {
68 isc_throw(BadValue, "NULL pointer received.");
69 } else if ((family != AF_INET) && (family != AF_INET6)) {
70 isc_throw(BadValue, "Invalid family type. Only AF_INET and AF_INET6"
71 << "are supported");
72 }
73
74 BOOST_STATIC_ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
75 char addr_str[INET6_ADDRSTRLEN];
76 inet_ntop(family, data, addr_str, INET6_ADDRSTRLEN);
77 return IOAddress(string(addr_str));
78}
79
80std::vector<uint8_t>
82 if (asio_address_.is_v4()) {
83 const boost::asio::ip::address_v4::bytes_type bytes4 =
84 asio_address_.to_v4().to_bytes();
85 return (std::vector<uint8_t>(bytes4.begin(), bytes4.end()));
86 }
87
88 // Not V4 address, so must be a V6 address (else we could never construct
89 // this object).
90 const boost::asio::ip::address_v6::bytes_type bytes6 =
91 asio_address_.to_v6().to_bytes();
92 return (std::vector<uint8_t>(bytes6.begin(), bytes6.end()));
93}
94
95short
97 if (asio_address_.is_v4()) {
98 return (AF_INET);
99 } else {
100 return (AF_INET6);
101 }
102}
103
104bool
106 if (!asio_address_.is_v6()) {
107 return (false);
108 }
109 return (asio_address_.to_v6().is_link_local());
110}
111
112bool
114 if (!asio_address_.is_v6()) {
115 return (false);
116 }
117 return (asio_address_.to_v6().is_multicast());
118}
119
120uint32_t
122 if (asio_address_.is_v4()) {
123 return (asio_address_.to_v4().to_uint());
124 } else {
125 isc_throw(BadValue, "Can't convert " << toText()
126 << " address to IPv4.");
127 }
128}
129
130std::ostream&
131operator<<(std::ostream& os, const IOAddress& address) {
132 os << address.toText();
133 return (os);
134}
135
136IOAddress
138 if (a.getFamily() != b.getFamily()) {
139 isc_throw(BadValue, "Both addresses have to be the same family");
140 }
141 if (a.isV4()) {
142 // Subtracting v4 is easy. We have a conversion function to uint32_t.
143 return (IOAddress(a.toUint32() - b.toUint32()));
144 } else {
145 // v6 is more involved.
146
147 // Let's extract the raw data first.
148 vector<uint8_t> a_vec = a.toBytes();
149 vector<uint8_t> b_vec = b.toBytes();
150
151 // ... and prepare the result
152 vector<uint8_t> result(V6ADDRESS_LEN,0);
153
154 // Carry is a boolean, but to avoid its frequent casting, let's
155 // use uint8_t. Also, some would prefer to call it borrow, but I prefer
156 // carry. Somewhat relevant discussion here:
157 // http://en.wikipedia.org/wiki/Carry_flag#Carry_flag_vs._Borrow_flag
158 uint8_t carry = 0;
159
160 // Now perform subtraction with borrow.
161 for (int i = a_vec.size() - 1; i >= 0; --i) {
162 result[i] = a_vec[i] - b_vec[i] - carry;
163 carry = (a_vec[i] < b_vec[i] + carry);
164 }
165
166 return (fromBytes(AF_INET6, &result[0]));
167 }
168}
169
172 std::vector<uint8_t> packed(addr.toBytes());
173
174 // Start increasing the least significant byte
175 for (int i = packed.size() - 1; i >= 0; --i) {
176 // if we haven't overflowed (0xff -> 0x0), than we are done
177 if (++packed[i] != 0) {
178 break;
179 }
180 }
181
182 return (IOAddress::fromBytes(addr.getFamily(), &packed[0]));
183}
184
185size_t
186hash_value(const IOAddress& address) {
187 if (address.isV4()) {
188 boost::hash<uint32_t> hasher;
189 return (hasher(address.toUint32()));
190 } else {
191 boost::hash<std::vector<uint8_t> > hasher;
192 return (hasher(address.toBytes()));
193 }
194}
195
196} // namespace asiolink
197} // 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.