]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#4274] Checkpoint: less UDP only
authorFrancis Dupont <fdupont@isc.org>
Fri, 23 Jan 2026 11:54:50 +0000 (12:54 +0100)
committerFrancis Dupont <fdupont@isc.org>
Mon, 9 Feb 2026 21:05:45 +0000 (22:05 +0100)
src/hooks/dhcp/radius/radius.cc
src/hooks/dhcp/radius/radius.h
src/hooks/dhcp/radius/radius_messages.cc
src/hooks/dhcp/radius/radius_messages.h
src/hooks/dhcp/radius/radius_messages.mes
src/hooks/dhcp/radius/radius_request.cc
src/hooks/dhcp/radius/radius_request.h
src/hooks/dhcp/radius/radius_status.cc
src/hooks/dhcp/radius/radius_status.h
src/hooks/dhcp/radius/radius_tls.cc

index 5d9ae32a6f0baf47682f2fe5af8199d4b2582e7a..772c2e7f502722d966c9a7eeea6f3065ac4c94da 100644 (file)
@@ -32,7 +32,7 @@ using namespace isc::util;
 namespace isc {
 namespace radius {
 
-UdpClient::UdpClient(const IOServicePtr& io_service, size_t thread_pool_size)
+UdpClient::UdpClient(const IOServicePtr& io_service, unsigned thread_pool_size)
     : io_service_(io_service), thread_pool_size_(thread_pool_size) {
     // Do nothing in ST mode.
     if (thread_pool_size == 0) {
@@ -56,7 +56,7 @@ UdpClient::~UdpClient() {
     stop();
 }
 
-size_t
+unsigned
 UdpClient::getThreadPoolSize() const {
     return (thread_pool_size_);
 }
@@ -276,6 +276,7 @@ RadiusImpl::startServices() {
     ConstElementPtr const& dhcp_config(
         CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
     bool multi_threaded(false);
+    unsigned thread_pool_size(0);
     uint32_t dhcp_threads(0);
     uint32_t dummy_queue_size(0);
     CfgMultiThreading::extract(dhcp_config, multi_threaded, dhcp_threads,
@@ -284,22 +285,26 @@ RadiusImpl::startServices() {
     if (multi_threaded) {
         // When threads are configured as zero, use the same number as DHCP
         // threads. If that is also zero, auto-detect.
-        unsigned thread_pool_size(thread_pool_size_);
         if (thread_pool_size_ == 0) {
             if (dhcp_threads == 0) {
                 uint32_t const hardware_threads(
                     MultiThreadingMgr::detectThreadCount());
                 if (hardware_threads == 0) {
                     // Keep it single-threaded.
-                    return;
+                    multi_threaded = false;
+                    thread_pool_size = 0;
                 } else {
                     thread_pool_size = hardware_threads;
                 }
             } else {
                 thread_pool_size = dhcp_threads;
             }
+        } else {
+            thread_pool_size = thread_pool_size_;
         }
+    }
 
+    if (multi_threaded) {
         // Schedule a start of the services. This ensures we begin after
         // the dust has settled and Kea MT mode has been firmly established.
         io_service_->post([this, thread_pool_size]() {
@@ -342,6 +347,24 @@ RadiusImpl::serveAccounting() const {
     return (common_ && common_->enabled_);
 }
 
+const Servers&
+RadiusImpl::getAccessServers() const {
+    if (proto_ != PW_PROTO_TLS) {
+        return (auth_->servers_);
+    } else {
+        return (common_->servers_);
+    }
+}
+
+const Servers&
+RadiusImpl::getAccountingServers() const {
+    if (proto_ != PW_PROTO_TLS) {
+        return (acct_->servers_);
+    } else {
+        return (common_->servers_);
+    }
+}
+
 void
 RadiusImpl::setAccessIdleTimer() {
     if (shutdown_) {
index 9f1d29247934281ec0e8fd2b3baad6ce9e9b761e..f455fd2b8ac08efc5a41d4a6ed82d38cbc586c4b 100644 (file)
@@ -44,7 +44,7 @@ public:
     /// The value 0 means that MT is disabled.
     /// deferred until a subsequent call to @ref start().
     UdpClient(const asiolink::IOServicePtr& io_service,
-              size_t thread_pool_size = 0);
+              unsigned thread_pool_size = 0);
 
     /// @brief Destructor.
     ~UdpClient();
@@ -85,7 +85,7 @@ public:
     /// @brief the maximum size of the thread pool.
     ///
     /// @return the maximum size of the thread pool.
-    size_t getThreadPoolSize() const;
+    unsigned getThreadPoolSize() const;
 
     /// @brief Register Exchange.
     ///
@@ -202,6 +202,16 @@ public:
     /// @return true is accounting is served, false otherwise.
     bool serveAccounting() const;
 
+    /// @brief Get servers for access.
+    ///
+    /// @return Servers to use with access servers.
+    const Servers& getAccessServers() const;
+
+    /// @brief Get servers for accounting.
+    ///
+    /// @return Servers to use with accounting servers.
+    const Servers& getAccountingServers() const;
+
     /// @brief Set the access idle timer.
     void setAccessIdleTimer();
 
index 186d52f81fb5ec9cb2c93a790e2bc55620ff6c4e..0e7e8ab0651f0e87ab333616fc6bcfa202e29801 100644 (file)
@@ -97,6 +97,10 @@ extern const isc::log::MessageID RADIUS_SESSION_HISTORY_OPEN_FAILED = "RADIUS_SE
 extern const isc::log::MessageID RADIUS_SESSION_HISTORY_STORED = "RADIUS_SESSION_HISTORY_STORED";
 extern const isc::log::MessageID RADIUS_SESSION_HISTORY_STORE_FAILED = "RADIUS_SESSION_HISTORY_STORE_FAILED";
 extern const isc::log::MessageID RADIUS_THREAD_POOL_STARTED = "RADIUS_THREAD_POOL_STARTED";
+extern const isc::log::MessageID RADIUS_TLS_STATUS = "RADIUS_TLS_STATUS";
+extern const isc::log::MessageID RADIUS_TLS_STATUS_ERROR = "RADIUS_TLS_STATUS_ERROR";
+extern const isc::log::MessageID RADIUS_TLS_STATUS_FAILED = "RADIUS_TLS_STATUS_FAILED";
+extern const isc::log::MessageID RADIUS_TLS_STATUS_SUCCEED = "RADIUS_TLS_STATUS_SUCCEED";
 
 } // namespace radius
 } // namespace isc
@@ -194,6 +198,10 @@ const char* values[] = {
     "RADIUS_SESSION_HISTORY_STORED", "Storing to the session history file succeeded: stored %1 records",
     "RADIUS_SESSION_HISTORY_STORE_FAILED", "Writing to the session history file %1 failed: %2 (stored %3 over %4 records)",
     "RADIUS_THREAD_POOL_STARTED", "RADIUS thread pool started with %1 threads.",
+    "RADIUS_TLS_STATUS", "send Status-Server with %1",
+    "RADIUS_TLS_STATUS_ERROR", "received error response to Status-Server: %1 (%2) with %3",
+    "RADIUS_TLS_STATUS_FAILED", "Status-Server failed: return code %1 (%2)",
+    "RADIUS_TLS_STATUS_SUCCEED", "received valid response to Status-Server",
     NULL
 };
 
index 98c66422a37e81949f02c3c855585545c3bb25aa..1f69ec20364bf64cf26e85c60a3eb8fbf3f4ca5b 100644 (file)
@@ -98,6 +98,10 @@ extern const isc::log::MessageID RADIUS_SESSION_HISTORY_OPEN_FAILED;
 extern const isc::log::MessageID RADIUS_SESSION_HISTORY_STORED;
 extern const isc::log::MessageID RADIUS_SESSION_HISTORY_STORE_FAILED;
 extern const isc::log::MessageID RADIUS_THREAD_POOL_STARTED;
+extern const isc::log::MessageID RADIUS_TLS_STATUS;
+extern const isc::log::MessageID RADIUS_TLS_STATUS_ERROR;
+extern const isc::log::MessageID RADIUS_TLS_STATUS_FAILED;
+extern const isc::log::MessageID RADIUS_TLS_STATUS_SUCCEED;
 
 } // namespace radius
 } // namespace isc
index b6b97aa8c6d4f7621c627501f35e0da0773a2f4e..7bc0d57c64e12e2484b4938f86ec826d7f88e244 100644 (file)
@@ -440,3 +440,23 @@ are displayed.
 % RADIUS_THREAD_POOL_STARTED RADIUS thread pool started with %1 threads.
 This informational message is issued when the thread pool is started.
 The number of threads is displayed.
+
+% RADIUS_TLS_STATUS send Status-Server with %1
+Logged at debug log level 40.
+This debug message is issued when starting to send a Status-Server message
+to common TLS servers. The message attributes are logged.
+
+% RADIUS_TLS_STATUS_ERROR received error response to Status-Server: %1 (%2) with %3
+This error message indicates that a valid response to Status-Server message
+was received from common TLS servers but with an unexpected code or an
+Error-Cause attribute. The response details are logged.
+
+% RADIUS_TLS_STATUS_FAILED Status-Server failed: return code %1 (%2)
+Logged at debug log level 40.
+This debug message is issued when no valid response to Status-Server message
+was received from common TLS servers.
+
+% RADIUS_TLS_STATUS_SUCCEED received valid response to Status-Server
+Logged at debug log level 40.
+This debug message indicates that a valid response to Status-Server message
+was received from common TLS servers.
index 4840f667ef7319b4c0a13b7e543a22ba3132361f..93900a73b7978067101bf2da0d82b7ee631dabd4 100644 (file)
@@ -54,9 +54,9 @@ RadiusRequest::RadiusRequest(const MsgCode code,
     unsigned maxretries = RadiusImpl::instance().retries_;
     Servers servers;
     if (code == PW_ACCESS_REQUEST) {
-        servers = RadiusImpl::instance().auth_->servers_;
+        servers = RadiusImpl::instance().getAccessServers();
     } else {
-        servers = RadiusImpl::instance().acct_->servers_;
+        servers = RadiusImpl::instance().getAccountingServers();
     }
     if (sync) {
         exchange_.reset(new Exchange(request, maxretries, servers));
index f96e434affcf426f0b68743061c7f34cc2a87ce3..838facf1342ce645dee9d727378acd64cd5be290 100644 (file)
@@ -20,11 +20,13 @@ namespace isc {
 namespace radius {
 
 /// @brief Type of callback for authentication termination.
+///
 /// First argument is the result code, second is the attribute collection
 /// from server response.
 typedef std::function<void(int, AttributesPtr)> CallbackAuth;
 
 /// @brief Type of callback for accounting termination.
+///
 /// The argument is the result code.
 typedef std::function<void(int)> CallbackAcct;
 
@@ -39,6 +41,7 @@ typedef std::function<void(int)> CallbackAcct;
 uint32_t getNASPort(uint32_t subnet_id);
 
 /// @brief Base class for communication with servers.
+///
 /// It represents the common part of authentication/authorization and
 /// accounting communication.
 class RadiusRequest {
@@ -61,6 +64,7 @@ public:
     virtual ~RadiusRequest() = default;
 
     /// @brief Start communication.
+    ///
     /// In synchronous mode it returns when exchange(s) is(are) finished,
     /// in asynchronous mode it initiates the (first) exchange.
     virtual void start() {
@@ -68,6 +72,8 @@ public:
     }
 
     /// @brief Get the error code.
+    ///
+    /// @return The error code.
     int getRC() const {
         return (exchange_->getRC());
     }
index c5db47526116807f5abc09d91799b4ba14b11224..10396a0623ff651bccf7bee908a3609a110956a7 100644 (file)
@@ -10,6 +10,7 @@
 #include <radius_accounting.h>
 #include <radius_status.h>
 #include <radius_log.h>
+#include <radius_tls.h>
 #include <sstream>
 
 using namespace isc::asiolink;
@@ -173,5 +174,77 @@ RadiusAcctStatus::invokeCallback(const CallbackAcct& callback,
     RadiusImpl::instance().unregisterExchange(exchange);
 }
 
+RadiusTlsStatus::RadiusTlsStatus(const AttributesPtr& send_attrs,
+                                 const CallbackStatus& handler)
+  : RadiusStatus() {
+    AttributesPtr attrs;
+    if (send_attrs) {
+        attrs.reset(new Attributes(*send_attrs));
+    } else {
+        attrs.reset(new Attributes());
+    }
+    MessagePtr request(new Message(PW_STATUS_SERVER, 0, vector<uint8_t>(),
+                                   "to-be-set", attrs));
+    unsigned maxretries = RadiusImpl::instance().retries_;
+    Servers servers = RadiusImpl::instance().common_->servers_;
+    exchange_.reset(new Exchange(RadiusImpl::instance().getIOContext(),
+                                 request, maxretries, servers,
+                                 std::bind(&RadiusTlsStatus::invokeCallback,
+                                           handler, ph::_1)));
+}
+
+void
+RadiusTlsStatus::start() {
+    AttributesPtr send_attrs;
+    MessagePtr request = exchange_->getRequest();
+    if (request) {
+        send_attrs = request->getAttributes();
+    }
+    LOG_DEBUG(radius_logger, RADIUS_DBG_TRACE, RADIUS_TLS_STATUS)
+        .arg(send_attrs ? send_attrs->toText() : "no attributes");
+
+    RadiusStatus::start();
+}
+
+void
+RadiusTlsStatus::invokeCallback(const CallbackAcct& callback,
+                                const ExchangePtr exchange) {
+    // Should not happen...
+    if (!exchange) {
+        return;
+    }
+    int result = exchange->getRC();
+    if (result == OK_RC) {
+        LOG_DEBUG(radius_logger, RADIUS_DBG_TRACE, RADIUS_TLS_STATUS_SUCCEED);
+        RadiusImpl::instance().setAccessIdleTimer();
+
+        MessagePtr response = exchange->getResponse();
+        AttributesPtr resp_attrs;
+        uint8_t code = 0;
+        if (response) {
+            resp_attrs = response->getAttributes();
+            code = response->getCode();
+        }
+        if (((code != 0) && (code != PW_ACCESS_ACCEPT)) ||
+            (resp_attrs && (resp_attrs->count(PW_ERROR_CAUSE) > 0))) {
+            LOG_ERROR(radius_logger, RADIUS_TLS_STATUS_ERROR)
+                .arg(msgCodeToText(code))
+                .arg(static_cast<unsigned>(code))
+                .arg(resp_attrs ? resp_attrs->toText() : "no attributes");
+        }
+    } else {
+        LOG_DEBUG(radius_logger, RADIUS_DBG_TRACE, RADIUS_TLS_STATUS_FAILED)
+            .arg(result)
+            .arg(exchangeRCtoText(result));
+    }
+
+    if (callback) {
+        try {
+            callback(result);
+        } catch (...) {
+        }
+    }
+}
+
 } // end of namespace radius
 } // end of namespace isc
index 8795b89a344f1f8a7d65337905b5aa2f873a0e12..b2d73d096022fc2eff2c681a4730495ce41c35aa 100644 (file)
@@ -20,6 +20,7 @@ namespace isc {
 namespace radius {
 
 /// @brief Type of callback for status termination.
+///
 /// The argument is the result code.
 typedef std::function<void(int)> CallbackStatus;
 
@@ -35,6 +36,7 @@ public:
     virtual ~RadiusStatus() = default;
 
     /// @brief Start communication.
+    ///
     /// Initiates the (first) exchange.
     virtual void start() {
         exchange_->start();
@@ -80,6 +82,7 @@ protected:
 };
 
 /// @brief class for communication with access servers.
+///
 /// Only the asynchronous variant is defined.
 class RadiusAuthStatus : public RadiusStatus {
 public:
@@ -109,6 +112,7 @@ public:
 typedef boost::shared_ptr<RadiusAuthStatus> RadiusAuthStatusPtr;
 
 /// @brief class for communication with accounting servers.
+///
 /// Only the asynchronous variant is defined.
 class RadiusAcctStatus : public RadiusStatus {
 public:
@@ -137,6 +141,36 @@ public:
 /// @brief Pointer to accounting status.
 typedef boost::shared_ptr<RadiusAcctStatus> RadiusAcctStatusPtr;
 
+/// @brief class for communication with common TLS servers.
+///
+/// Only the asynchronous variant is defined.
+class RadiusTlsStatus : public RadiusStatus {
+public:
+
+    /// @brief Constructor.
+    ///
+    /// @param send_attrs Attributes to send.
+    /// @param handler Termination handler.
+    RadiusTlsStatus(const AttributesPtr& send_attrs,
+                    const CallbackStatus& handler);
+
+    /// @brief Destructor.
+    virtual ~RadiusTlsStatus() = default;
+
+    /// @brief Start communication.
+    virtual void start() override;
+
+    /// @brief Invoke access status callback
+    ///
+    /// @param callback Termination callback
+    /// @param exchange the exchange.
+    static void invokeCallback(const CallbackStatus& callback,
+                               const ExchangePtr exchange);
+};
+
+/// @brief Pointer to access status.
+typedef boost::shared_ptr<RadiusTlsStatus> RadiusTlsStatusPtr;
+
 } // end of namespace radius
 } // end of namespace isc
 #endif // RADIUS_STATUS_H
index d1993eda76556181ed25de4f332f655b1dfb099a..b21ddab6d0775769f163d0d1cb504cad4d7f9e4a 100644 (file)
@@ -41,8 +41,7 @@ RadiusTls::setIdleTimer() {
 void
 RadiusTls::IdleTimerCallback() {
     AttributesPtr send_attrs;
-    RadiusAuthStatusPtr handler(new RadiusAuthStatus(send_attrs, 0));
-    RadiusImpl::instance().registerExchange(handler->getExchange());
+    RadiusTlsStatusPtr handler(new RadiusTlsStatus(send_attrs, 0));
     handler->start();
 }