Kea  2.3.9
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>
9 #include <asiolink/io_address.h>
10 #include <asiolink/io_error.h>
11 #include <exceptions/exceptions.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 using namespace boost::asio;
23 using boost::asio::ip::udp;
24 using boost::asio::ip::tcp;
25 
26 using namespace std;
27 
28 namespace isc {
29 namespace asiolink {
30 
31 size_t
32 IOAddress::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.
38 IOAddress::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 
47 IOAddress::IOAddress(const boost::asio::ip::address& asio_address) :
48  asio_address_(asio_address)
49 {}
50 
51 IOAddress::IOAddress(uint32_t v4address):
52  asio_address_(boost::asio::ip::address_v4(v4address)) {
53 
54 }
55 
56 string
58  return (asio_address_.to_string());
59 }
60 
62 IOAddress::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 
77 std::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 
92 short
94  if (asio_address_.is_v4()) {
95  return (AF_INET);
96  } else {
97  return (AF_INET6);
98  }
99 }
100 
101 bool
103  if (!asio_address_.is_v6()) {
104  return (false);
105  }
106  return (asio_address_.to_v6().is_link_local());
107 }
108 
109 bool
111  if (!asio_address_.is_v6()) {
112  return (false);
113  }
114  return (asio_address_.to_v6().is_multicast());
115 }
116 
117 uint32_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 
127 std::ostream&
128 operator<<(std::ostream& os, const IOAddress& address) {
129  os << address.toText();
130  return (os);
131 }
132 
133 IOAddress
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 
167 IOAddress
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 
182 size_t
183 hash_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.