Coverage Report

Created: 2026-07-14 08:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/kea/src/hooks/dhcp/radius/client_exchange.h
Line
Count
Source
1
// Copyright (C) 2023-2026 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
#ifndef RADIUS_CLIENT_EXCHANGE_H
8
#define RADIUS_CLIENT_EXCHANGE_H
9
10
#include <client_attribute.h>
11
#include <client_message.h>
12
#include <client_server.h>
13
#include <asiolink/asio_wrapper.h>
14
#include <asiolink/interval_timer.h>
15
#include <asiolink/io_address.h>
16
#include <asiolink/io_service.h>
17
#include <asiolink/udp_socket.h>
18
#include <cc/cfg_to_element.h>
19
#include <cc/data.h>
20
#include <exceptions/exceptions.h>
21
#include <boost/enable_shared_from_this.hpp>
22
#include <boost/scoped_ptr.hpp>
23
#include <boost/shared_ptr.hpp>
24
#include <chrono>
25
#include <functional>
26
#include <list>
27
#include <mutex>
28
#include <string>
29
#include <vector>
30
31
namespace isc {
32
namespace radius {
33
34
/// @brief Exchange error codes.
35
///
36
/// @todo Move to Exchange class.
37
enum ExchangeRC {
38
    BADRESP_RC = -2,        // Got a bad response.
39
    ERROR_RC = -1,          // General error.
40
    OK_RC = 0,              // OK: no error.
41
    TIMEOUT_RC = 1,         // Timeout occurred.
42
    REJECT_RC = 2,          // Got an Access-Reject response.
43
    READBLOCK_RC = 3        // Get AGAIN or EWOULDBLOCK.
44
};
45
46
/// @brief ExchangeRC value -> name function.
47
///
48
/// @param rc the error code.
49
std::string exchangeRCtoText(const int rc);
50
51
/// @brief RADIUS exchange (forward declaration).
52
class Exchange;
53
54
/// @brief Type of shared pointers to RADIUS exchange object.
55
typedef boost::shared_ptr<Exchange> ExchangePtr;
56
57
/// @brief RADIUS Base Exchange.
58
class Exchange {
59
public:
60
    /// @brief Receive buffer size.
61
    static constexpr size_t BUF_LEN = 8192;
62
63
    /// @brief Type of UDP socket callback functions.
64
    typedef std::function<void(const boost::system::error_code ec,
65
                               const size_t size)> SocketCallback;
66
67
    /// @brief Type of RADIUS UDP sockets.
68
    typedef asiolink::UDPSocket<const SocketCallback> RadiusSocket;
69
70
    /// @brief Termination handler.
71
    typedef std::function<void(const ExchangePtr ex)> Handler;
72
73
    /// @brief Factory.
74
    ///
75
    /// Async version.
76
    ///
77
    /// @param io_service Reference to the IO service.
78
    /// @param request request message to send.
79
    /// @param maxretries maximum number of retries for a server.
80
    /// @param servers Servers.
81
    /// @param handler Termination handler.
82
    /// @param protocol Protocol (default to UDP).
83
    static ExchangePtr create(const asiolink::IOServicePtr io_service,
84
                              const MessagePtr& request,
85
                              unsigned maxretries,
86
                              const Servers& servers,
87
                              Handler handler,
88
                              RadiusProtocol protocol = PW_PROTO_UDP);
89
90
    /// @brief Factory.
91
    ///
92
    /// Sync version (UDP only).
93
    ///
94
    /// @param request request message to send.
95
    /// @param maxretries maximum number of retries for a server.
96
    /// @param servers Servers.
97
    static ExchangePtr create(const MessagePtr& request,
98
                              unsigned maxretries,
99
                              const Servers& servers);
100
101
    /// @brief Destructor.
102
0
    virtual ~Exchange() = default;
103
104
    /// @brief Get identifier.
105
    ///
106
    /// @return the identifier.
107
0
    const std::string& getId() const {
108
0
        return (identifier_);
109
0
    }
110
111
    /// @brief Get the error code.
112
    ///
113
    /// @return the error code.
114
0
    int getRC() const {
115
0
        return (rc_);
116
0
    }
117
118
    /// @brief Get the request.
119
    ///
120
    /// @return the request.
121
0
    MessagePtr getRequest() const {
122
0
        return (request_);
123
0
    }
124
125
    /// @brief Get the response.
126
    ///
127
    /// @return the response.
128
0
    MessagePtr getResponse() const {
129
0
        return (received_);
130
0
    }
131
132
    /// @brief Log reply messages.
133
    void logReplyMessages() const;
134
135
    /// @brief Start.
136
    virtual void start() = 0;
137
138
    /// @brief Shutdown.
139
    virtual void shutdown() = 0;
140
141
    /// @brief Process response.
142
    void processResponse();
143
144
protected:
145
    /// @brief Constructor.
146
    ///
147
    /// Async version.
148
    ///
149
    /// @param request request message to send.
150
    /// @param maxretries maximum number of retries for a server.
151
    /// @param servers Servers.
152
    /// @param handler Termination handler.
153
    Exchange(const MessagePtr& request,
154
             unsigned maxretries,
155
             const Servers& servers,
156
             Handler handler);
157
158
    /// @brief Constructor.
159
    ///
160
    /// Sync version.
161
    ///
162
    /// @param request request message to send.
163
    /// @param maxretries maximum number of retries for a server.
164
    /// @param servers Servers.
165
    Exchange(const MessagePtr& request,
166
             unsigned maxretries,
167
             const Servers& servers);
168
169
    /// @brief The identifier (random value in hexadecimal).
170
    std::string identifier_;
171
172
    /// @brief Sync / async flag.
173
    bool sync_;
174
175
    /// @brief Error/return code.
176
    int rc_;
177
178
    /// @brief Request message.
179
    MessagePtr request_;
180
181
    /// @brief Sent message.
182
    MessagePtr sent_;
183
184
    /// @brief Received message.
185
    MessagePtr received_;
186
187
    /// @brief Maximum number of retries for a server.
188
    /// @note 0 is a valid value which means no retry.
189
    unsigned maxretries_;
190
191
    /// @brief Servers (a copy which is what we need).
192
    Servers servers_;
193
194
    /// @brief Termination handler.
195
    Handler handler_;
196
197
    /// @brief Create identifier.
198
    void createIdentifier();
199
200
    /// @brief Build request.
201
    ///
202
    /// @param server Server where to send the request.
203
    /// @param start_time Start time of the exchange.
204
    void buildRequest(const ServerPtr& server,
205
                      std::chrono::steady_clock::time_point start_time);
206
};
207
208
/// @brief RADIUS/UDP exchange (forward declaration).
209
class UdpExchange;
210
211
/// @brief Type of shared pointers to RADIUS/UDP exchange object.
212
typedef boost::shared_ptr<UdpExchange> UdpExchangePtr;
213
214
/// @brief RADIUS/UDP Exchange.
215
class UdpExchange : public Exchange,
216
                    public boost::enable_shared_from_this<UdpExchange> {
217
public:
218
    /// @brief Constructor.
219
    ///
220
    /// Async version.
221
    ///
222
    /// @param io_service Reference to the IO service.
223
    /// @param request request message to send.
224
    /// @param maxretries maximum number of retries for a server.
225
    /// @param servers Servers.
226
    /// @param handler Termination handler.
227
    UdpExchange(const asiolink::IOServicePtr io_service,
228
                const MessagePtr& request,
229
                unsigned maxretries,
230
                const Servers& servers,
231
                Handler handler);
232
233
    /// @brief Constructor.
234
    ///
235
    /// Sync version.
236
    ///
237
    /// @param request request message to send.
238
    /// @param maxretries maximum number of retries for a server.
239
    /// @param servers Servers.
240
    UdpExchange(const MessagePtr& request,
241
                unsigned maxretries,
242
                const Servers& servers);
243
244
    /// @brief Destructor.
245
    virtual ~UdpExchange();
246
247
    /// @brief Start.
248
    virtual void start();
249
250
    /// @brief Shutdown.
251
    virtual void shutdown();
252
253
protected:
254
    /// @brief IO service (argument for async or internal for sync).
255
    asiolink::IOServicePtr io_service_;
256
257
    /// @brief Started flag.
258
    bool started_;
259
260
    /// @brief Terminated flag.
261
    bool terminated_;
262
263
    /// @brief Start time.
264
    std::chrono::steady_clock::time_point start_time_;
265
266
    /// @brief Socket.
267
    boost::scoped_ptr<RadiusSocket> socket_;
268
269
    /// @brief UDP endpoint.
270
    boost::scoped_ptr<asiolink::UDPEndpoint> ep_;
271
272
    /// @brief Interval timer.
273
    asiolink::IntervalTimerPtr timer_;
274
275
    /// @brief Current server.
276
    ServerPtr server_;
277
278
    /// @brief Current server index.
279
    ///
280
    /// The current server is either the server indexed by this in the table
281
    /// or when greater than the table size the first postponed server.
282
    size_t idx_;
283
284
    /// @brief Buffer.
285
    std::vector<uint8_t> buffer_;
286
287
    /// @brief Number of transmitted octests;
288
    size_t size_;
289
290
    /// @brief Retry counter.
291
    unsigned retries_;
292
293
    /// @brief List of postponed server indexes.
294
    std::list<size_t> postponed_;
295
296
    /// @brief State change mutex.
297
    boost::scoped_ptr<std::mutex> mutex_;
298
299
    /// @brief Build request.
300
    void buildRequest();
301
302
    /// @brief Instance open.
303
    void open();
304
305
    /// @brief Shutdown.
306
    virtual void shutdownInternal();
307
308
    /// @brief Class open / open next.
309
    ///
310
    /// @param ex the exchange.
311
0
    static void openNext(UdpExchangePtr ex) {
312
0
        ex->open();
313
0
    }
314
315
    /// @brief Sent handler.
316
    ///
317
    /// @param ex the exchange.
318
    /// @param ec Boost ASIO error code.
319
    /// @param size number of sent octets.
320
    static void sentHandler(UdpExchangePtr ex,
321
                            const boost::system::error_code ec,
322
                            const size_t size);
323
324
    /// @brief Received handler.
325
    ///
326
    /// @param ex the exchange.
327
    /// @param ec Boost ASIO error code.
328
    /// @param size number of received octets.
329
    static void receivedHandler(UdpExchangePtr ex,
330
                                const boost::system::error_code ec,
331
                                const size_t size);
332
333
    /// @brief Set timer.
334
    void setTimer();
335
336
    /// @brief Cancel timer.
337
    void cancelTimer();
338
339
    /// @brief Timeout handler.
340
    ///
341
    /// @param ex the exchange.
342
    static void timeoutHandler(UdpExchangePtr ex);
343
344
    /// @brief Terminate.
345
    void terminate();
346
};
347
348
/// @brief RADIUS/TCP exchange (forward declaration).
349
class TcpExchange;
350
351
/// @brief Type of shared pointers to RADIUS/TCP exchange object.
352
typedef boost::shared_ptr<TcpExchange> TcpExchangePtr;
353
354
/// @brief RADIUS/TCP (or RADIUS/TLS) Exchange.
355
class TcpExchange : public Exchange,
356
                    public boost::enable_shared_from_this<TcpExchange> {
357
public:
358
    /// @brief Constructor.
359
    ///
360
    /// Async version.
361
    ///
362
    /// @param request request message to send.
363
    /// @param maxretries maximum number of retries for a server.
364
    /// @param servers Servers.
365
    /// @param handler Termination handler.
366
    TcpExchange(const MessagePtr& request,
367
                unsigned maxretries,
368
                const Servers& servers,
369
                Handler handler);
370
371
    /// @note: no sync version.
372
373
    /// @brief Destructor.
374
0
    virtual ~TcpExchange() = default;
375
376
    /// @brief Start.
377
    virtual void start();
378
379
    /// @brief Shutdown.
380
    virtual void shutdown();
381
382
protected:
383
    /// @brief Start time.
384
    std::chrono::steady_clock::time_point start_time_;
385
386
    /// @brief Current server.
387
    ServerPtr server_;
388
389
    /// @brief Response wire data.
390
    isc::tcp::WireDataPtr response_;
391
392
    /// @brief Build request.
393
    void buildRequest();
394
395
    /// @brief Request handler.
396
    ///
397
    /// @param ex Point to the Exchange.
398
    /// @param ec Boost error code.
399
    /// @param response Pointer to response wire data.
400
    /// @param error_msg Error message.
401
    static void RequestHandler(TcpExchangePtr ex,
402
                               const boost::system::error_code& ec,
403
                               const isc::tcp::WireDataPtr& response,
404
                               const std::string& error_msg);
405
406
    /// @brief Complete check.
407
    ///
408
    /// @param response Pointer to response wire data.
409
    /// @param error_msg Reference to the error message.
410
    /// @return status (>0 complete, 0 incomplete, <0 error).
411
    static int CompleteCheck(const isc::tcp::WireDataPtr& response,
412
                             std::string& error_msg);
413
};
414
415
} // end of namespace isc::radius
416
} // end of namespace isc
417
418
#endif