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