Kea 3.1.5
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
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
25using namespace isc;
26using namespace isc::asiolink;
27using namespace isc::data;
28using namespace isc::util;
29using namespace std;
30using namespace std::chrono;
31namespace ph = std::placeholders;
32
34struct 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 }
46 freeaddrinfo(addrinfo_);
47 }
48 struct addrinfo *addrinfo_;
49};
50
51
52namespace isc {
53namespace radius {
54
55string
56protocolToText(const int proto) {
57 ostringstream result;
58 switch (proto) {
59 case PW_PROTO_UDP:
60 return ("UDP");
61 case PW_PROTO_TCP:
62 return ("TCP");
63 case PW_PROTO_TLS:
64 return ("TLS");
65 default:
66 result << "unknown transport protocol " << proto;
67 return (result.str());
68 }
69}
70
72Server::getAddress(const string& name) {
73 AddrInfo res(name);
74 short family = res.addrinfo_->ai_family;
75 if (family == AF_INET) {
76 struct sockaddr_in* sin4 =
77 reinterpret_cast<struct sockaddr_in*>(res.addrinfo_->ai_addr);
78 vector<uint8_t> in4(4);
79 memmove(&in4[0], &sin4->sin_addr, 4);
80 return (IOAddress::fromBytes(AF_INET, &in4[0]));
81 } else if (family == AF_INET6) {
82 struct sockaddr_in6* sin6 =
83 reinterpret_cast<struct sockaddr_in6*>(res.addrinfo_->ai_addr);
84 vector<uint8_t> in6(16);
85 memmove(&in6[0], &sin6->sin6_addr, 16);
86 return (IOAddress::fromBytes(AF_INET6, &in6[0]));
87 }
88 isc_throw(BadValue, "getaddrinfo('" << name << ") returned unknown family "
89 << family);
90}
91
94 vector<uint8_t> bindest = dest.toBytes();
95 vector<uint8_t> binsrc(bindest.size());
96 if (bindest.size() == 4) {
97 struct sockaddr_in dest4;
98 socklen_t len = sizeof(dest4);
99 memset(&dest4, 0, len);
100 dest4.sin_family = AF_INET;
101#ifdef HAVE_SA_LEN
102 dest4.sin_len = len;
103#endif
104 memmove(&dest4.sin_addr, &bindest[0], 4);
105 dest4.sin_port = htons(11812);
106 int fd = socket(PF_INET, SOCK_DGRAM, 0);
107 if (fd < 0) {
108 isc_throw(Unexpected, "socket() failed: " << strerror(errno));
109 }
110 int err = connect(fd, reinterpret_cast<const struct sockaddr*>(&dest4),
111 len);
112 if (err < 0) {
113 static_cast<void>(close(fd));
114 isc_throw(Unexpected, "connect() failed: " << strerror(errno));
115 }
116 struct sockaddr_in src4;
117 memset(&src4, 0, len);
118 err = getsockname(fd, reinterpret_cast<struct sockaddr*>(&src4), &len);
119 static_cast<void>(close(fd));
120 if ((err < 0) || (len != sizeof(src4))) {
121 isc_throw(Unexpected, "getsockname() failed: " << strerror(errno));
122 }
123 memmove(&binsrc[0], &src4.sin_addr, 4);
124 return (IOAddress::fromBytes(AF_INET, &binsrc[0]));
125 } else if (bindest.size() == 16) {
126 struct sockaddr_in6 dest6;
127 socklen_t len = sizeof(dest6);
128 memset(&dest6, 0, len);
129 dest6.sin6_family = AF_INET6;
130#ifdef HAVE_SA_LEN
131 dest6.sin6_len = len;
132#endif
133 memmove(&dest6.sin6_addr, &bindest[0], 16);
134 dest6.sin6_port = htons(11812);
135 int fd = socket(PF_INET6, SOCK_DGRAM, 0);
136 if (fd < 0) {
137 isc_throw(Unexpected, "socket() failed: " << strerror(errno));
138 }
139 int err = connect(fd, reinterpret_cast<const struct sockaddr*>(&dest6),
140 len);
141 if (err < 0) {
142 static_cast<void>(close(fd));
143 isc_throw(Unexpected, "connect() failed: " << strerror(errno));
144 }
145 struct sockaddr_in6 src6;
146 memset(&src6, 0, len);
147 err = getsockname(fd, reinterpret_cast<struct sockaddr*>(&src6), &len);
148 static_cast<void>(close(fd));
149 if ((err < 0) || (len != sizeof(src6))) {
150 isc_throw(Unexpected, "getsockname() failed: " << strerror(errno));
151 }
152 memmove(&binsrc[0], &src6.sin6_addr, 16);
153 return (IOAddress::fromBytes(AF_INET6, &binsrc[0]));
154 } else {
155 isc_throw(Unexpected, "address length is not 4 nor 16: "
156 << bindest.size());
157 }
158}
159
161 if (!secret_.empty()) {
162 memset(&secret_[0], 0, secret_.size());
163 }
164 secret_.clear();
165}
166
167
168void
170 if (peer_addr_.getFamily() != local_addr.getFamily()) {
171 isc_throw(BadValue, "address family mismatch: peer "
172 << peer_addr_.toText() << ", local " << local_addr.toText());
173 }
174 local_addr_ = local_addr;
175}
176
177void
178Server::setTimeout(unsigned timeout) {
179 if (static_cast<uint64_t>(timeout) > numeric_limits<long>::max() / 1000) {
180 isc_throw(OutOfRange, "too large timeout " << timeout
181 << " > " << std::numeric_limits<long>::max() / 1000);
182 }
183 timeout_ = (timeout == 0 ? 1 : timeout);
184}
185
186void
187Server::setSecret(const string& secret) {
188 if (secret.empty()) {
189 isc_throw(BadValue, "empty secret");
190 }
191 secret_ = secret;
192}
193
194steady_clock::time_point
197
198 return (deadtime_end_);
199}
200
201void
202Server::setDeadtimeEnd(const steady_clock::time_point& deadtime_end) {
204
205 deadtime_end_ = deadtime_end;
206}
207
211
212 // Peer address.
213 result->set("peer-address", Element::create(peer_addr_.toText()));
214
215 // Port.
216 result->set("peer-port", Element::create(peer_port_));
217
218 // Local address.
219 result->set("local-address", Element::create(local_addr_.toText()));
220
221 // TLS context.
222 if (tls_context_) {
223 result->set("tls-context", Element::create(true));
224 }
225
226 // Secret.
227 result->set("secret", Element::create(secret_));
228
229 // Timeout.
230 result->set("timeout", Element::create(static_cast<long long>(timeout_)));
231
232 // Deadtime.
233 result->set("deadtime", Element::create(static_cast<long long>(deadtime_)));
234
235 if (deadtime_ != 0) {
237
238 auto delta = deadtime_end_ - steady_clock().now();
239 seconds secs = duration_cast<seconds>(delta);
240 result->set("deadtime-end",
241 Element::create(static_cast<long long>(secs.count())));
242 }
243 return (result);
244}
245
246} // end of namespace isc::radius
247} // end of namespace isc
static ElementPtr create(const Position &pos=ZERO_POSITION())
Create a NullElement.
Definition data.cc:299
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:354
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
A generic exception that is thrown when an unexpected error condition occurs.
void setTimeout(const unsigned timeout)
Set timeout.
asiolink::IOAddress local_addr_
Local address.
boost::scoped_ptr< std::mutex > mutex_
Mutex to protect the state.
void setSecret(const std::string &secret)
Set secret.
void setLocalAddress(const asiolink::IOAddress &local_addr)
Set local address.
const asiolink::IOAddress peer_addr_
Peer address.
data::ElementPtr toElement() const override
Unparse server.
unsigned deadtime_
Deadtime i.e. hold-down delay.
virtual ~Server()
Destructor.
static asiolink::IOAddress getSrcAddress(const asiolink::IOAddress &dest)
Get the source address from a destination address.
std::chrono::steady_clock::time_point deadtime_end_
Deadtime end i.e.
std::chrono::steady_clock::time_point getDeadtimeEnd() const
Get deadtime end.
static asiolink::IOAddress getAddress(const std::string &name)
Get an address from a name.
unsigned timeout_
Timeout.
asiolink::TlsContextPtr tls_context_
TLS context.
void setDeadtimeEnd(const std::chrono::steady_clock::time_point &deadtime_end)
Set deadtime end.
std::string secret_
Secret.
uint16_t peer_port_
Peer port.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< Element > ElementPtr
Definition data.h:29
string protocolToText(const int proto)
Transport protocol to text.
Defines the logger used by the top-level component of kea-lfc.
RAII wrapper over struct addrinfo.
AddrInfo(string const &hostname)
struct addrinfo * addrinfo_
RAII lock object to protect the code in the same scope with a mutex.