Kea: http_command_mgr.cc Source File

| Kea 3.0.2-git

http_command_mgr.cc
Go to the documentation of this file.
1// Copyright (C) 2024-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/asio_wrapper.h>
10#include <config/command_mgr.h>
11#include <config/config_log.h>
12#include <config/http_command_mgr.h>
13#include <config/http_command_response_creator_factory.h>
14#include <config/http_command_response_creator.h>
15#include <config/timeouts.h>
16#include <sstream>
17#include <vector>
18
19using namespace isc;
20using namespace isc::asiolink;
21using namespace isc::config;
22using namespace isc::data;
23using namespace isc::dhcp;
24using namespace isc::http;
25using namespace std;
26
27namespace isc {
28namespace config {
29
31 class HttpCommandMgrImpl {
32public:
33
35 HttpCommandMgrImpl()
36 : io_service_(), timeout_(TIMEOUT_AGENT_RECEIVE_COMMAND),
37 idle_timeout_(TIMEOUT_AGENT_IDLE_CONNECTION_TIMEOUT),
38 use_external_(true) {
39 }
40
44 void openCommandSockets(const isc::data::ConstElementPtr config);
45
52 void openCommandSocket(const isc::data::ConstElementPtr config);
53
58 void closeCommandSocket(HttpSocketInfoPtr info, bool remove);
59
63 void closeCommandSockets(bool remove = true);
64
71 ConstHttpListenerPtr getHttpListener(HttpSocketInfoPtr info) const;
72
74 IOServicePtr io_service_;
75
77 long timeout_;
78
80 long idle_timeout_;
81
83 std::map<std::pair<IOAddress, uint16_t>, HttpSocketInfoPtr> sockets_;
84
86 bool use_external_;
87};
88
89void
90HttpCommandMgrImpl::openCommandSockets(const isc::data::ConstElementPtr config) {
91 if (!config) {
92 isc_throw(BadSocketInfo, "Missing config parameters, can't create socket.");
93 }
94
95 if (config->getType() != Element::list) {
96 isc_throw(DhcpConfigError, "expected list type ("
97 << config->getPosition() << ")");
98 }
99
100 for (auto const& socket : config->listValue()) {
101 openCommandSocket(socket);
102 }
103
104 auto copy = sockets_;
105 for (auto const& data : copy) {
106 if (data.second->usable_) {
107 // If the connection can be used (just created) or reused, keep it
108 // in the list and clear the flag. It will be marked again on next
109 // configuration event if needed.
110 data.second->usable_ = false;
111 } else {
112 // If the connection can not be reused, stop it and remove it from the list.
113 closeCommandSocket(data.second, true);
114 }
115 }
116}
117
118void
119HttpCommandMgrImpl::openCommandSocket(const isc::data::ConstElementPtr config) {
120 if (!config) {
121 isc_throw(BadSocketInfo, "Missing config parameters, can't create socket.");
122 }
123
124 HttpCommandConfigPtr cmd_config(new HttpCommandConfig(config));
125
126 IOAddress server_address = cmd_config->getSocketAddress();
127 uint16_t server_port = cmd_config->getSocketPort();
128
129 // Search for the specific connection and reuse the existing one if found.
130 auto it = sockets_.find(std::make_pair(server_address, server_port));
131 if (it != sockets_.end()) {
132 auto listener = it->second->listener_;
133 if (listener) {
134 // Reconfig keeping the same address and port.
135 if (listener->getTlsContext()) {
136 if (cmd_config->getTrustAnchor().empty()) {
137 // Can not switch from HTTPS to HTTP
138 LOG_ERROR(command_logger, HTTP_COMMAND_MGR_HTTPS_SERVICE_REUSE_FAILED)
139 .arg(server_address.toText())
140 .arg(server_port);
141 isc_throw(BadValue,
142 "Can not switch from HTTPS to HTTP sockets using the same address and port.");
143 } else {
144 // Apply TLS settings each time.
145 TlsContextPtr tls_context;
146 TlsContext::configure(tls_context,
147 TlsRole::SERVER,
148 cmd_config->getTrustAnchor(),
149 cmd_config->getCertFile(),
150 cmd_config->getKeyFile(),
151 cmd_config->getCertRequired());
152 // Overwrite the authentication setup, the http headers and the emulation flag
153 // in the response creator config.
154 it->second->config_->setAuthConfig(cmd_config->getAuthConfig());
155 it->second->config_->setHttpHeaders(cmd_config->getHttpHeaders());
156 it->second->config_->setEmulateAgentResponse(cmd_config->getEmulateAgentResponse());
157 listener->setTlsContext(tls_context);
158 LOG_INFO(command_logger, HTTP_COMMAND_MGR_HTTPS_SERVICE_UPDATED)
159 .arg(server_address.toText())
160 .arg(server_port);
161 }
162 } else {
163 if (!cmd_config->getTrustAnchor().empty()) {
164 // Can not switch from HTTP to HTTPS
165 LOG_ERROR(command_logger, HTTP_COMMAND_MGR_HTTP_SERVICE_REUSE_FAILED)
166 .arg(server_address.toText())
167 .arg(server_port);
168 isc_throw(BadValue,
169 "Can not switch from HTTP to HTTPS sockets using the same address and port.");
170 } else {
171 // Overwrite the authentication setup, the http headers and the emulation flag
172 // in the response creator config.
173 it->second->config_->setAuthConfig(cmd_config->getAuthConfig());
174 it->second->config_->setHttpHeaders(cmd_config->getHttpHeaders());
175 it->second->config_->setEmulateAgentResponse(cmd_config->getEmulateAgentResponse());
176 LOG_INFO(command_logger, HTTP_COMMAND_MGR_HTTP_SERVICE_UPDATED)
177 .arg(server_address.toText())
178 .arg(server_port);
179 }
180 }
181 }
182 // If the connection can be reused, mark it as usable.
183 it->second->usable_ = true;
184 return;
185 }
186
187 // Connection not found so it needs to be created.
188 // When TLS is enabled configure it.
189 bool use_https = false;
190 TlsContextPtr tls_context;
191 if (!cmd_config->getCertFile().empty()) {
192 TlsContext::configure(tls_context,
193 TlsRole::SERVER,
194 cmd_config->getTrustAnchor(),
195 cmd_config->getCertFile(),
196 cmd_config->getKeyFile(),
197 cmd_config->getCertRequired());
198 use_https = true;
199 }
200
201 // Create response creator factory first. It will be used to
202 // generate response creators. Each response creator will be used
203 // to generate answer to specific request.
204 HttpResponseCreatorFactoryPtr rfc(new HttpCommandResponseCreatorFactory(cmd_config));
205
206 // Create HTTP listener. It will open up a TCP socket and be
207 // prepared to accept incoming connection.
208 HttpListenerPtr http_listener
209 (new HttpListener(io_service_,
210 server_address,
211 server_port,
212 tls_context,
213 rfc,
214 HttpListener::RequestTimeout(timeout_),
215 HttpListener::IdleTimeout(idle_timeout_)));
216
217 // Pass the use external socket flag.
218 http_listener->addExternalSockets(use_external_);
219
220 // Instruct the HTTP listener to actually open socket, install
221 // callback and start listening.
222 http_listener->start();
223
224 HttpSocketInfoPtr socket_info(new HttpSocketInfo());
225 socket_info->config_ = cmd_config;
226 socket_info->listener_ = http_listener;
227
228 sockets_[std::make_pair(server_address, server_port)] = socket_info;
229
230 // Ok, seems we're good to go.
231 LOG_INFO(command_logger, HTTP_COMMAND_MGR_SERVICE_STARTED)
232 .arg(use_https ? "HTTPS" : "HTTP")
233 .arg(server_address.toText())
234 .arg(server_port);
235}
236
237void
238HttpCommandMgrImpl::closeCommandSocket(HttpSocketInfoPtr info, bool remove) {
239 bool use_https = false;
240 if (info) {
241 ostringstream ep;
242 use_https = !info->config_->getCertFile().empty();
243 ep << "bound to address " << info->config_->getSocketAddress()
244 << " port " << info->config_->getSocketPort();
245
246 LOG_INFO(command_logger, HTTP_COMMAND_MGR_SERVICE_STOPPING)
247 .arg(use_https ? "HTTPS" : "HTTP")
248 .arg(ep.str());
249 info->listener_->stop();
250 if (remove) {
251 auto it = sockets_.find(std::make_pair(info->config_->getSocketAddress(), info->config_->getSocketPort()));
252 if (it != sockets_.end()) {
253 sockets_.erase(it);
254 }
255 }
256 // We have stopped listeners but there may be some pending handlers
257 // related to these listeners. Need to invoke these handlers.
258 try {
259 io_service_->pollOne();
260 } catch (...) {
261 }
262 } else {
263 closeCommandSockets(remove);
264 }
265}
266
267void
268HttpCommandMgrImpl::closeCommandSockets(bool remove) {
269 auto copy = sockets_;
270 for (auto const& data : copy) {
271 closeCommandSocket(data.second, remove);
272 }
273}
274
275 ConstHttpListenerPtr
276HttpCommandMgrImpl::getHttpListener(HttpSocketInfoPtr info) const {
277 // Return the most recent listener or null.
278 if (info) {
279 auto it = sockets_.find(std::make_pair(info->config_->getSocketAddress(), info->config_->getSocketPort()));
280 if (it != sockets_.end()) {
281 return (it->second->listener_);
282 }
283 } else if (sockets_.size()) {
284 return (sockets_.begin()->second->listener_);
285 }
286 return (ConstHttpListenerPtr());
287}
288
289 HttpCommandMgr&
290HttpCommandMgr::instance() {
291 static HttpCommandMgr http_cmd_mgr;
292 return (http_cmd_mgr);
293}
294
295HttpCommandMgr::HttpCommandMgr() : impl_(new HttpCommandMgrImpl()) {
296}
297
298void
299HttpCommandMgr::setIOService(const IOServicePtr& io_service) {
300 impl_->io_service_ = io_service;
301}
302
303void
304HttpCommandMgr::setConnectionTimeout(const long timeout) {
305 impl_->timeout_ = timeout;
306}
307
308void
309HttpCommandMgr::setIdleConnectionTimeout(const long timeout) {
310 impl_->idle_timeout_ = timeout;
311}
312
313void
314HttpCommandMgr::addExternalSockets(bool use_external) {
315 impl_->use_external_ = use_external;
316}
317
318void
319HttpCommandMgr::openCommandSocket(const isc::data::ConstElementPtr config) {
320 impl_->openCommandSocket(config);
321}
322
323void
324HttpCommandMgr::openCommandSockets(const isc::data::ConstElementPtr config) {
325 impl_->openCommandSockets(config);
326}
327
328void
329HttpCommandMgr::closeCommandSocket(HttpSocketInfoPtr info, bool remove) {
330 impl_->closeCommandSocket(info, remove);
331}
332
333void
334HttpCommandMgr::closeCommandSockets() {
335 impl_->closeCommandSockets();
336}
337
338 ConstHttpListenerPtr
339HttpCommandMgr::getHttpListener(HttpSocketInfoPtr info) const {
340 return (impl_->getHttpListener(info));
341}
342
343} // end of isc::config
344} // end of isc
asio_wrapper.h
Element::list
@ list
Definition data.h:146
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::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::config::BadSocketInfo
An exception indicating that specified socket parameters are invalid.
Definition command_mgr.h:17
isc::config::HttpCommandConfig
HTTP command config aka HTTP control socket info class.
Definition http_command_config.h:22
isc::config::HttpCommandMgrImpl
Implementation of the HttpCommandMgr.
Definition http_command_mgr.cc:31
isc::config::HttpCommandMgrImpl::use_external_
bool use_external_
Use external sockets flag.
Definition http_command_mgr.cc:86
isc::config::HttpCommandMgrImpl::sockets_
std::map< std::pair< IOAddress, uint16_t >, HttpSocketInfoPtr > sockets_
The HTTP/HTTPS socket data (configuration, listener, etc.).
Definition http_command_mgr.cc:83
isc::config::HttpCommandMgrImpl::openCommandSockets
void openCommandSockets(const isc::data::ConstElementPtr config)
Open http control sockets using configuration.
Definition http_command_mgr.cc:90
isc::config::HttpCommandMgrImpl::idle_timeout_
long idle_timeout_
Idle connection timeout.
Definition http_command_mgr.cc:80
isc::config::HttpCommandMgrImpl::io_service_
IOServicePtr io_service_
Pointer to the IO service.
Definition http_command_mgr.cc:74
isc::config::HttpCommandMgrImpl::closeCommandSockets
void closeCommandSockets(bool remove=true)
Close control socket.
Definition http_command_mgr.cc:268
isc::config::HttpCommandMgrImpl::HttpCommandMgrImpl
HttpCommandMgrImpl()
Constructor.
Definition http_command_mgr.cc:35
isc::config::HttpCommandMgrImpl::closeCommandSocket
void closeCommandSocket(HttpSocketInfoPtr info, bool remove)
Close control socket.
Definition http_command_mgr.cc:238
isc::config::HttpCommandMgrImpl::openCommandSocket
void openCommandSocket(const isc::data::ConstElementPtr config)
Open http control socket using configuration.
Definition http_command_mgr.cc:119
isc::config::HttpCommandMgrImpl::timeout_
long timeout_
Connection timeout.
Definition http_command_mgr.cc:77
isc::config::HttpCommandMgrImpl::getHttpListener
ConstHttpListenerPtr getHttpListener(HttpSocketInfoPtr info) const
Returns a const pointer to the HTTP listener.
Definition http_command_mgr.cc:276
isc::config::HttpCommandMgr
HTTP Commands Manager implementation for the Kea servers.
Definition http_command_mgr.h:23
isc::config::HttpCommandMgr::openCommandSocket
void openCommandSocket(const isc::data::ConstElementPtr config)
Open http control socket using configuration.
Definition http_command_mgr.cc:319
isc::config::HttpCommandMgr::setIdleConnectionTimeout
void setIdleConnectionTimeout(const long timeout)
Override default idle connection timeout.
Definition http_command_mgr.cc:309
isc::config::HttpCommandMgr::getHttpListener
isc::http::ConstHttpListenerPtr getHttpListener(HttpSocketInfoPtr info=HttpSocketInfoPtr()) const
Returns a const pointer to the HTTP listener.
Definition http_command_mgr.cc:339
isc::config::HttpCommandMgr::closeCommandSockets
void closeCommandSockets()
Close http control sockets.
Definition http_command_mgr.cc:334
isc::config::HttpCommandMgr::setConnectionTimeout
void setConnectionTimeout(const long timeout)
Override default connection timeout.
Definition http_command_mgr.cc:304
isc::config::HttpCommandMgr::addExternalSockets
void addExternalSockets(bool use_external=true)
Use external sockets flag.
Definition http_command_mgr.cc:314
isc::config::HttpCommandMgr::instance
static HttpCommandMgr & instance()
HttpCommandMgr is a singleton class.
Definition http_command_mgr.cc:290
isc::config::HttpCommandMgr::setIOService
void setIOService(const asiolink::IOServicePtr &io_service)
Sets IO service to be used by the http command manager.
Definition http_command_mgr.cc:299
isc::config::HttpCommandMgr::openCommandSockets
void openCommandSockets(const isc::data::ConstElementPtr config)
Open http control sockets using configuration.
Definition http_command_mgr.cc:324
isc::config::HttpCommandMgr::closeCommandSocket
void closeCommandSocket(HttpSocketInfoPtr info=HttpSocketInfoPtr(), bool remove=true)
Close http control socket.
Definition http_command_mgr.cc:329
isc::config::HttpCommandResponseCreatorFactory
HTTP response creator factory for HTTP control socket.
Definition http_command_response_creator_factory.h:32
isc::dhcp::DhcpConfigError
To be removed. Please use ConfigError instead.
Definition dhcp_config_error.h:58
isc::http::HttpListener
HTTP listener.
Definition listener.h:52
command_mgr.h
config_log.h
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition exceptions/exceptions.h:210
http_command_mgr.h
http_command_response_creator.h
http_command_response_creator_factory.h
LOG_ERROR
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition macros.h:32
LOG_INFO
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition macros.h:20
isc::asiolink
Definition addr_utilities.cc:170
isc::asiolink::TlsContextPtr
boost::shared_ptr< TlsContext > TlsContextPtr
The type of shared pointers to TlsContext objects.
Definition common_tls.h:37
isc::asiolink::IOServicePtr
boost::shared_ptr< IOService > IOServicePtr
Defines a smart pointer to an IOService instance.
Definition io_service.h:28
isc::asiolink::SERVER
@ SERVER
Definition common_tls.h:31
isc::config
Definition command_interpreter.cc:23
isc::config::HTTP_COMMAND_MGR_HTTPS_SERVICE_UPDATED
const isc::log::MessageID HTTP_COMMAND_MGR_HTTPS_SERVICE_UPDATED
Definition config_messages.h:39
isc::config::TIMEOUT_AGENT_IDLE_CONNECTION_TIMEOUT
constexpr long TIMEOUT_AGENT_IDLE_CONNECTION_TIMEOUT
Timeout for the idle connection to be closed.
Definition timeouts.h:24
isc::config::HTTP_COMMAND_MGR_SERVICE_STARTED
const isc::log::MessageID HTTP_COMMAND_MGR_SERVICE_STARTED
Definition config_messages.h:42
isc::config::HttpSocketInfoPtr
boost::shared_ptr< HttpSocketInfo > HttpSocketInfoPtr
Pointer to a HttpSocketInfo object.
Definition http_command_config.h:256
isc::config::HTTP_COMMAND_MGR_SERVICE_STOPPING
const isc::log::MessageID HTTP_COMMAND_MGR_SERVICE_STOPPING
Definition config_messages.h:43
isc::config::HTTP_COMMAND_MGR_HTTP_SERVICE_REUSE_FAILED
const isc::log::MessageID HTTP_COMMAND_MGR_HTTP_SERVICE_REUSE_FAILED
Definition config_messages.h:40
isc::config::HTTP_COMMAND_MGR_HTTP_SERVICE_UPDATED
const isc::log::MessageID HTTP_COMMAND_MGR_HTTP_SERVICE_UPDATED
Definition config_messages.h:41
isc::config::HttpCommandConfigPtr
boost::shared_ptr< HttpCommandConfig > HttpCommandConfigPtr
Pointer to a HttpCommandConfig object.
Definition http_command_config.h:233
isc::config::command_logger
isc::log::Logger command_logger("commands")
Command processing Logger.
Definition config_log.h:21
isc::config::HTTP_COMMAND_MGR_HTTPS_SERVICE_REUSE_FAILED
const isc::log::MessageID HTTP_COMMAND_MGR_HTTPS_SERVICE_REUSE_FAILED
Definition config_messages.h:38
isc::config::TIMEOUT_AGENT_RECEIVE_COMMAND
constexpr long TIMEOUT_AGENT_RECEIVE_COMMAND
Timeout for the Control Agent to receive command over the RESTful interface.
Definition timeouts.h:21
isc::data
Definition base_stamped_element.cc:12
isc::data::copy
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
Definition data.cc:1420
isc::data::ConstElementPtr
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
isc::db::info
@ info
Definition db_log.h:120
isc::dhcp
Definition dhcp4/client_handler.cc:20
isc::http
Definition auth_config.h:19
isc::http::ConstHttpListenerPtr
boost::shared_ptr< const HttpListener > ConstHttpListenerPtr
Pointer to the const HttpListener.
Definition listener.h:159
isc::http::HttpListenerPtr
boost::shared_ptr< HttpListener > HttpListenerPtr
Pointer to the HttpListener.
Definition listener.h:156
isc::http::HttpResponseCreatorFactoryPtr
boost::shared_ptr< HttpResponseCreatorFactory > HttpResponseCreatorFactoryPtr
Pointer to the HttpResponseCreatorFactory.
Definition response_creator_factory.h:54
isc
Defines the logger used by the top-level component of kea-lfc.
Definition agent_parser.cc:148
isc::config::HttpSocketInfo
Structure used to store HTTP/HTTPS connection data.
Definition http_command_config.h:237
isc::http::HttpListener::IdleTimeout
Idle connection timeout.
Definition listener.h:67
isc::http::HttpListener::RequestTimeout
HTTP request timeout value.
Definition listener.h:56
timeouts.h