| Kea 3.0.2-git

client_server.cc
Go to the documentation of this file.
1// Copyright (C) 2023-2025 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>
8
9#include <asiolink/io_address.h>
10#include <cryptolink/crypto_rng.h>
11#include <util/multi_threading_mgr.h>
12#include <client_server.h>
13#include <radius_log.h>
14
15#include <sys/types.h>
16#include <sys/socket.h>
17#include <netinet/in.h>
18#include <netdb.h>
19
20#include <cerrno>
21#include <chrono>
22#include <limits>
23#include <sstream>
24
25 using namespace isc;
26 using namespace isc::asiolink;
27 using namespace isc::data;
28 using namespace isc::util;
29 using namespace std;
30 using namespace std::chrono;
31 namespace ph = std::placeholders;
32
34 struct AddrInfo {
35 AddrInfo(string const& hostname) : addrinfo_(0) {
36 int const err(getaddrinfo(hostname.c_str(), 0, 0, &addrinfo_));
37 if (err != 0) {
38 string const errmsg(gai_strerror(err));
39 isc_throw(BadValue, "failed to resolve '" << hostname << "': " << errmsg);
40 }
41 if (!addrinfo_ || !addrinfo_->ai_addr) {
42 isc_throw(BadValue, "getaddrinfo('" << hostname << ") returned null");
43 }
44 }
45 ~AddrInfo() {
46 freeaddrinfo(addrinfo_);
47 }
48 struct addrinfo *addrinfo_;
49};
50
51
52 namespace isc {
53 namespace radius {
54
55 IOAddress
56 Server::getAddress(const string& name) {
57 AddrInfo res(name);
58 short family = res.addrinfo_->ai_family;
59 if (family == AF_INET) {
60 struct sockaddr_in* sin4 =
61 reinterpret_cast<struct sockaddr_in*>(res.addrinfo_->ai_addr);
62 vector<uint8_t> in4(4);
63 memmove(&in4[0], &sin4->sin_addr, 4);
64 return (IOAddress::fromBytes(AF_INET, &in4[0]));
65 } else if (family == AF_INET6) {
66 struct sockaddr_in6* sin6 =
67 reinterpret_cast<struct sockaddr_in6*>(res.addrinfo_->ai_addr);
68 vector<uint8_t> in6(16);
69 memmove(&in6[0], &sin6->sin6_addr, 16);
70 return (IOAddress::fromBytes(AF_INET6, &in6[0]));
71 }
72 isc_throw(BadValue, "getaddrinfo('" << name << ") returned unknown family "
73 << family);
74}
75
76 IOAddress
77 Server::getSrcAddress(const IOAddress& dest) {
78 vector<uint8_t> bindest = dest.toBytes();
79 vector<uint8_t> binsrc(bindest.size());
80 if (bindest.size() == 4) {
81 struct sockaddr_in dest4;
82 socklen_t len = sizeof(dest4);
83 memset(&dest4, 0, len);
84 dest4.sin_family = AF_INET;
85#ifdef HAVE_SA_LEN
86 dest4.sin_len = len;
87#endif
88 memmove(&dest4.sin_addr, &bindest[0], 4);
89 dest4.sin_port = htons(11812);
90 int fd = socket(PF_INET, SOCK_DGRAM, 0);
91 if (fd < 0) {
92 isc_throw(Unexpected, "socket() failed: " << strerror(errno));
93 }
94 int err = connect(fd, reinterpret_cast<const struct sockaddr*>(&dest4),
95 len);
96 if (err < 0) {
97 static_cast<void>(close(fd));
98 isc_throw(Unexpected, "connect() failed: " << strerror(errno));
99 }
100 struct sockaddr_in src4;
101 memset(&src4, 0, len);
102 err = getsockname(fd, reinterpret_cast<struct sockaddr*>(&src4), &len);
103 static_cast<void>(close(fd));
104 if ((err < 0) || (len != sizeof(src4))) {
105 isc_throw(Unexpected, "getsockname() failed: " << strerror(errno));
106 }
107 memmove(&binsrc[0], &src4.sin_addr, 4);
108 return (IOAddress::fromBytes(AF_INET, &binsrc[0]));
109 } else if (bindest.size() == 16) {
110 struct sockaddr_in6 dest6;
111 socklen_t len = sizeof(dest6);
112 memset(&dest6, 0, len);
113 dest6.sin6_family = AF_INET6;
114#ifdef HAVE_SA_LEN
115 dest6.sin6_len = len;
116#endif
117 memmove(&dest6.sin6_addr, &bindest[0], 16);
118 dest6.sin6_port = htons(11812);
119 int fd = socket(PF_INET6, SOCK_DGRAM, 0);
120 if (fd < 0) {
121 isc_throw(Unexpected, "socket() failed: " << strerror(errno));
122 }
123 int err = connect(fd, reinterpret_cast<const struct sockaddr*>(&dest6),
124 len);
125 if (err < 0) {
126 static_cast<void>(close(fd));
127 isc_throw(Unexpected, "connect() failed: " << strerror(errno));
128 }
129 struct sockaddr_in6 src6;
130 memset(&src6, 0, len);
131 err = getsockname(fd, reinterpret_cast<struct sockaddr*>(&src6), &len);
132 static_cast<void>(close(fd));
133 if ((err < 0) || (len != sizeof(src6))) {
134 isc_throw(Unexpected, "getsockname() failed: " << strerror(errno));
135 }
136 memmove(&binsrc[0], &src6.sin6_addr, 16);
137 return (IOAddress::fromBytes(AF_INET6, &binsrc[0]));
138 } else {
139 isc_throw(Unexpected, "address length is not 4 nor 16: "
140 << bindest.size());
141 }
142}
143
144 Server::~Server() {
145 if (!secret_.empty()) {
146 memset(&secret_[0], 0, secret_.size());
147 }
148 secret_.clear();
149}
150
151
152 void
153 Server::setLocalAddress(const IOAddress& local_addr) {
154 if (peer_addr_.getFamily() != local_addr.getFamily()) {
155 isc_throw(BadValue, "address family mismatch: peer "
156 << peer_addr_.toText() << ", local " << local_addr.toText());
157 }
158 local_addr_ = local_addr;
159}
160
161 void
162 Server::setTimeout(unsigned timeout) {
163 if (static_cast<uint64_t>(timeout) > numeric_limits<long>::max() / 1000) {
164 isc_throw(OutOfRange, "too large timeout " << timeout
165 << " > " << std::numeric_limits<long>::max() / 1000);
166 }
167 timeout_ = (timeout == 0 ? 1 : timeout);
168}
169
170 void
171 Server::setSecret(const string& secret) {
172 if (secret.empty()) {
173 isc_throw(BadValue, "empty secret");
174 }
175 secret_ = secret;
176}
177
178steady_clock::time_point
179 Server::getDeadtimeEnd() const {
180 MultiThreadingLock lock(*mutex_);
181
182 return (deadtime_end_);
183}
184
185 void
186 Server::setDeadtimeEnd(const steady_clock::time_point& deadtime_end) {
187 MultiThreadingLock lock(*mutex_);
188
189 deadtime_end_ = deadtime_end;
190}
191
192 ElementPtr
193 Server::toElement() const {
194 ElementPtr result = Element::createMap();
195
196 // Peer address.
197 result->set("peer-address", Element::create(peer_addr_.toText()));
198
199 // Port.
200 result->set("peer-port", Element::create(peer_port_));
201
202 // Local address.
203 result->set("local-address", Element::create(local_addr_.toText()));
204
205 // Secret.
206 result->set("secret", Element::create(secret_));
207
208 // Timeout.
209 result->set("timeout", Element::create(static_cast<long long>(timeout_)));
210
211 // Deadtime.
212 result->set("deadtime", Element::create(static_cast<long long>(deadtime_)));
213
214 if (deadtime_ != 0) {
215 MultiThreadingLock lock(*mutex_);
216
217 auto delta = deadtime_end_ - steady_clock().now();
218 seconds secs = duration_cast<seconds>(delta);
219 result->set("deadtime-end",
220 Element::create(static_cast<long long>(secs.count())));
221 }
222 return (result);
223}
224
225} // end of namespace isc::radius
226} // end of namespace isc
Element::create
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition data.cc:249
Element::createMap
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:304
isc::BadValue
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Definition exceptions/exceptions.h:132
isc::OutOfRange
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
Definition exceptions/exceptions.h:115
isc::Unexpected
A generic exception that is thrown when an unexpected error condition occurs.
Definition exceptions/exceptions.h:153
isc::asiolink::IOAddress
The IOAddress class represents an IP addresses (version agnostic).
Definition io_address.h:45
isc::asiolink::IOAddress::toText
std::string toText() const
Convert the address to a string.
Definition io_address.cc:61
isc::asiolink::IOAddress::toBytes
std::vector< uint8_t > toBytes() const
Return address as set of bytes.
Definition io_address.cc:81
isc::asiolink::IOAddress::getFamily
short getFamily() const
Returns the address family.
Definition io_address.cc:96
isc::asiolink::IOAddress::fromBytes
static IOAddress fromBytes(short family, const uint8_t *data)
Creates an address from over wire data.
Definition io_address.cc:66
isc::radius::Server::setTimeout
void setTimeout(const unsigned timeout)
Set timeout.
Definition client_server.cc:162
isc::radius::Server::local_addr_
asiolink::IOAddress local_addr_
Local address.
Definition client_server.h:176
isc::radius::Server::mutex_
boost::scoped_ptr< std::mutex > mutex_
Mutex to protect the state.
Definition client_server.h:193
isc::radius::Server::setSecret
void setSecret(const std::string &secret)
Set secret.
Definition client_server.cc:171
isc::radius::Server::setLocalAddress
void setLocalAddress(const asiolink::IOAddress &local_addr)
Set local address.
Definition client_server.cc:153
isc::radius::Server::peer_addr_
const asiolink::IOAddress peer_addr_
Peer address.
Definition client_server.h:170
isc::radius::Server::toElement
data::ElementPtr toElement() const override
Unparse server.
Definition client_server.cc:193
isc::radius::Server::deadtime_
unsigned deadtime_
Deadtime i.e. hold-down delay.
Definition client_server.h:185
isc::radius::Server::~Server
virtual ~Server()
Destructor.
Definition client_server.cc:144
isc::radius::Server::getSrcAddress
static asiolink::IOAddress getSrcAddress(const asiolink::IOAddress &dest)
Get the source address from a destination address.
Definition client_server.cc:77
isc::radius::Server::deadtime_end_
std::chrono::steady_clock::time_point deadtime_end_
Deadtime end i.e.
Definition client_server.h:190
isc::radius::Server::getDeadtimeEnd
std::chrono::steady_clock::time_point getDeadtimeEnd() const
Get deadtime end.
Definition client_server.cc:179
isc::radius::Server::getAddress
static asiolink::IOAddress getAddress(const std::string &name)
Get an address from a name.
Definition client_server.cc:56
isc::radius::Server::timeout_
unsigned timeout_
Timeout.
Definition client_server.h:182
isc::radius::Server::setDeadtimeEnd
void setDeadtimeEnd(const std::chrono::steady_clock::time_point &deadtime_end)
Set deadtime end.
Definition client_server.cc:186
isc::radius::Server::secret_
std::string secret_
Secret.
Definition client_server.h:179
isc::radius::Server::peer_port_
uint16_t peer_port_
Peer port.
Definition client_server.h:173
client_server.h
crypto_rng.h
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition exceptions/exceptions.h:210
io_address.h
multi_threading_mgr.h
isc::asiolink
Definition addr_utilities.cc:170
isc::data
Definition base_stamped_element.cc:12
isc::data::ElementPtr
boost::shared_ptr< Element > ElementPtr
Definition data.h:28
isc::radius
Definition cfg_attribute.cc:21
isc::util
Definition time_utils.cc:43
isc
Defines the logger used by the top-level component of kea-lfc.
Definition agent_parser.cc:148
radius_log.h
AddrInfo
RAII wrapper over struct addrinfo.
Definition client_server.cc:34
AddrInfo::AddrInfo
AddrInfo(string const &hostname)
Definition client_server.cc:35
AddrInfo::addrinfo_
struct addrinfo * addrinfo_
Definition client_server.cc:48
AddrInfo::~AddrInfo
~AddrInfo()
Definition client_server.cc:45
isc::util::MultiThreadingLock
RAII lock object to protect the code in the same scope with a mutex.
Definition multi_threading_mgr.h:349