Kea 3.1.1
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
56Server::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
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
145 if (!secret_.empty()) {
146 memset(&secret_[0], 0, secret_.size());
147 }
148 secret_.clear();
149}
150
151
152void
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
161void
162Server::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
170void
171Server::setSecret(const string& secret) {
172 if (secret.empty()) {
173 isc_throw(BadValue, "empty secret");
174 }
175 secret_ = secret;
176}
177
178steady_clock::time_point
181
182 return (deadtime_end_);
183}
184
185void
186Server::setDeadtimeEnd(const steady_clock::time_point& deadtime_end) {
188
189 deadtime_end_ = deadtime_end;
190}
191
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) {
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
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition data.cc:249
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:304
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.
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:28
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.