Kea 3.3.1
lease_query_callouts.cc
Go to the documentation of this file.
1// Copyright (C) 2020-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#include <config.h>
8
12#include <hooks/hooks.h>
13#include <dhcpsrv/cfgmgr.h>
14#include <lease_query_log.h>
16#include <blq_service.h>
17#include <process/daemon.h>
18#include <stats/stats_mgr.h>
19
20#include <string>
21#include <vector>
22
23using namespace isc;
24using namespace isc::asiolink;
25using namespace isc::lease_query;
26using namespace isc::data;
27using namespace isc::db;
28using namespace isc::dhcp;
29using namespace isc::hooks;
30using namespace isc::log;
31using namespace isc::process;
32using namespace isc::stats;
33using namespace std;
34
35namespace {
41ConstElementPtr getConfig(LibraryHandle& handle) {
42 const std::vector<std::string> names = handle.getParameterNames();
44
45 for (auto const& name : names) {
46 ConstElementPtr value = handle.getParameter(name);
47 if (value) {
48 config->set(name, value);
49 }
50 }
51
52 // Note checkKeywords() will throw DhcpConfigError if there is a problem.
54 return (config);
55}
56
63int extended_info4_upgrade(CalloutHandle& handle) {
64 return (LeaseQueryImpl4::upgradeHandler(handle));
65}
66
73int extended_info6_upgrade(CalloutHandle& handle) {
74 return (LeaseQueryImpl6::upgradeHandler(handle));
75}
76} // end of anonymous namespace
77
78extern "C" {
79
103 if (status == CalloutHandle::NEXT_STEP_DROP) {
104 return (0);
105 }
106
107 // Get the received message.
108 Pkt4Ptr query;
109 handle.getArgument("query4", query);
110 try {
111 // If it's not already unpacked, unpack it
113 query->unpack();
114 }
115 } catch (const std::exception& ex) {
118 .arg(query->getRemoteAddr().toText())
119 .arg(query->getLocalAddr().toText())
120 .arg(query->getIface())
121 .arg(ex.what());
122 // Increase the statistics of parse failures and dropped packets.
123 StatsMgr::instance().addValue("pkt4-parse-failed",
124 static_cast<int64_t>(1));
125 StatsMgr::instance().addValue("pkt4-receive-drop",
126 static_cast<int64_t>(1));
128 return (0);
129 }
130
131 // Not a lease query, so return without handling it.
132 // Also skipping DHCPv4-over-DHCPv6 queries as they can bypass
133 // the sender access control.
134 // Make sure status is SKIP so it doesn't get unpacked again.
135 if ((query->getType() != DHCPLEASEQUERY) || query->isDhcp4o6()) {
137 return (0);
138 }
139
142 StatsMgr::instance().addValue("pkt4-lease-query-received", static_cast<int64_t>(1));
143
144 bool invalid = false;
145 try {
147 } catch (const std::exception& ex) {
148 // Failed to parse the packet.
152 .arg(ex.what());
153
155 if (!invalid) {
156 StatsMgr::instance().addValue("pkt4-processing-failed",
157 static_cast<int64_t>(1));
158 }
159 StatsMgr::instance().addValue("pkt4-receive-drop",
160 static_cast<int64_t>(1));
161 return (0);
162 }
163
164 // We always set status to DROP as the query has been handled.
166 return (0);
167}
168
192 if (status == CalloutHandle::NEXT_STEP_DROP) {
193 return (0);
194 }
195
196 // Get the received message.
197 Pkt6Ptr query;
198 handle.getArgument("query6", query);
199
200 try {
201 // If it's not already unpacked, unpack it.
203 query->unpack();
204 }
205 } catch (const std::exception& ex) {
208 .arg(query->getRemoteAddr().toText())
209 .arg(query->getLocalAddr().toText())
210 .arg(query->getIface())
211 .arg(ex.what());
212 // Increase the statistics of parse failures and dropped packets.
213 StatsMgr::instance().addValue("pkt6-parse-failed",
214 static_cast<int64_t>(1));
215 StatsMgr::instance().addValue("pkt6-receive-drop",
216 static_cast<int64_t>(1));
218 return (0);
219 }
220
221 // Not a lease query, so return without handling it.
222 // Make sure status is SKIP so it doesn't get unpacked again.
223 if (query->getType() != DHCPV6_LEASEQUERY) {
225 return (0);
226 }
227
230 StatsMgr::instance().addValue("pkt6-lease-query-received", static_cast<int64_t>(1));
231
232 bool invalid = false;
233 try {
235 } catch (const std::exception& ex) {
236 // Log that we failed to process the packet.
240 .arg(ex.what());
241
243 if (!invalid) {
244 StatsMgr::instance().addValue("pkt6-processing-failed",
245 static_cast<int64_t>(1));
246 }
247 StatsMgr::instance().addValue("pkt6-receive-drop",
248 static_cast<int64_t>(1));
249 return (0);
250 }
251
252 // We always set status to DROP as the query has been handled.
254 return (0);
255}
256
260int load(LibraryHandle& handle) {
261 try {
262
263 // Make the hook library not loadable by d2.
264 uint16_t family = CfgMgr::instance().getFamily();
265 const std::string& proc_name = Daemon::getProcName();
266 if (family == AF_INET) {
267 if (proc_name != "kea-dhcp4") {
268 isc_throw(isc::Unexpected, "Bad process name: " << proc_name
269 << ", expected kea-dhcp4");
270 }
271
272 handle.registerCommandCallout("extended-info4-upgrade",
273 extended_info4_upgrade);
274 } else {
275 if (proc_name != "kea-dhcp6") {
276 isc_throw(isc::Unexpected, "Bad process name: " << proc_name
277 << ", expected kea-dhcp6");
278 }
279
280 handle.registerCommandCallout("extended-info6-upgrade",
281 extended_info6_upgrade);
282 }
283
284 ConstElementPtr config = getConfig(handle);
287 } catch (const std::exception& ex) {
289 .arg(ex.what());
292 return (1);
293 }
294
296 return (0);
297}
298
302int unload() {
303 // Helps current running works to terminate.
305
307
308 // Stop and Destroy the BulkLeaseQueryService instance.
310
311 // Destroy the LeaseQueryImpl instance.
313
315 return (0);
316}
317
329
339 // Only repopulate the list if CB updated subnets.
340 AuditEntryCollectionPtr audit_entries;
341 handle.getArgument("audit_entries", audit_entries);
342
343 auto const& object_type_idx = audit_entries->get<AuditEntryObjectTypeTag>();
344 auto range = object_type_idx.equal_range("dhcp6_subnet");
345 if (std::distance(range.first, range.second)) {
346 try {
348 const LeaseQueryImpl6& impl6 = dynamic_cast<const LeaseQueryImpl6&>
350 LeaseQueryImpl6& impl = const_cast<LeaseQueryImpl6&>(impl6);
351 impl.populatePrefixLengthList(cfg);
352 } catch (const std::exception& ex) {
353 const string error("Error: populatePrefixLengthList() failed");
354 handle.setArgument("error", ex.what());
355 return (1);
356 }
357 }
358
359 return (0);
360}
361
369 try {
370 SrvConfigPtr cfg;
371 handle.getArgument("server_config", cfg);
372 const LeaseQueryImpl6& impl6 = dynamic_cast<const LeaseQueryImpl6&>
374 LeaseQueryImpl6& impl = const_cast<LeaseQueryImpl6&>(impl6);
375 impl.populatePrefixLengthList(cfg);
376 } catch (const std::exception& ex) {
378 const string error("Error: populatePrefixLengthList() failed");
379 handle.setArgument("error", ex.what());
380 return (1);
381 }
382
385 return (0);
386}
387
392 return (1);
393}
394
395} // end extern "C"
CalloutNextStep
Specifies allowed next steps.
@ NEXT_STEP_DROP
drop the packet
@ NEXT_STEP_SKIP
skip the next processing step
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:355
A generic exception that is thrown when an unexpected error condition occurs.
static void checkKeywords(const SimpleKeywords &keywords, isc::data::ConstElementPtr scope)
Checks acceptable keywords with their expected type.
uint16_t getFamily() const
Returns address family.
Definition cfgmgr.h:246
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition cfgmgr.cc:29
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition cfgmgr.cc:116
Per-packet callout handle.
@ NEXT_STEP_DROP
drop the packet
CalloutNextStep getStatus() const
Returns the next processing step.
void setStatus(const CalloutNextStep next)
Sets the next processing step.
void getArgument(const std::string &name, T &value) const
Get argument.
void setArgument(const std::string &name, T value)
Set argument.
isc::data::ConstElementPtr getParameter(const std::string &name)
Returns configuration parameter for the library.
std::vector< std::string > getParameterNames()
Returns names of configuration parameters for the library.
void registerCommandCallout(const std::string &command_name, CalloutPtr callout)
Register control command handler.
static void reset()
Reset the sole instance of BulkLeaseQueryService.
static void doStartListener()
Start the listener.
static int upgradeHandler(hooks::CalloutHandle &handle)
Upgrade extended information.
static std::string leaseQueryLabel(const dhcp::Pkt4Ptr &packet)
Convenience method for generating per packet logging info.
Provides configuration and control flow for processing queries.
static std::string leaseQueryLabel(const dhcp::Pkt6Ptr &packet)
Convenience method for generating per packet logging info.
static int upgradeHandler(hooks::CalloutHandle &handle)
Upgrade extended information.
static void createImpl(uint16_t family, isc::data::ConstElementPtr config)
Creates the LeaseQueryImpl singleton.
static LeaseQueryImpl & getMutableImpl()
Fetch the LeaseQueryImpl singleton.
static const LeaseQueryImpl & getImpl()
Fetch the LeaseQueryImpl singleton.
static void destroyImpl()
Destroy the LeaseQueryImpl singleton.
static bool terminated_
Terminated flag.
static const isc::data::SimpleKeywords LEASE_QUERY_KEYWORDS
Keywords for Lease Query configuration.
isc::asiolink::IOServicePtr getIOService()
Get the hook I/O service.
virtual void processQuery(isc::dhcp::PktPtr base_query, bool &invalid) const =0
Processes a single client Lease Query.
static std::string getProcName()
returns the process name This value is used as when forming the default PID file name
Definition daemon.cc:155
static StatsMgr & instance()
Statistics Manager accessor method.
@ DHCPV6_LEASEQUERY
Definition dhcp6.h:222
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
void addValue(const std::string &name, const int64_t value)
Records incremental integer observation.
int dhcp4_srv_configured(CalloutHandle &)
dhcp4_srv_configured callout implementation.
int multi_threading_compatible()
This function is called to retrieve the multi-threading compatibility.
int unload()
This function is called when the library is unloaded.
int dhcp6_srv_configured(CalloutHandle &handle)
dhcp6_srv_configured callout implementation.
int cb6_updated(CalloutHandle &handle)
This callout is called at the "cb6_updated" hook.
int buffer4_receive(CalloutHandle &handle)
This callout is called at the "buffer4_receive" hook.
int buffer6_receive(CalloutHandle &handle)
This callout is called at the "buffer6_receive" hook.
int load(LibraryHandle &handle)
This function is called when the library is loaded.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition macros.h:32
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition macros.h:20
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition macros.h:14
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:30
boost::shared_ptr< Element > ElementPtr
Definition data.h:29
@ error
Definition db_log.h:126
boost::shared_ptr< AuditEntryCollection > AuditEntryCollectionPtr
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition pkt4.h:556
boost::shared_ptr< SrvConfig > SrvConfigPtr
Non-const pointer to the SrvConfig.
@ DHCPLEASEQUERY
Definition dhcp4.h:244
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition pkt6.h:31
const isc::log::MessageID LEASE_QUERY_UNLOAD_OK
const isc::log::MessageID DHCP4_LEASE_QUERY_RECEIVED
const isc::log::MessageID LEASE_QUERY_LOAD_OK
const isc::log::MessageID LEASE_QUERY_LOAD_FAILED
const isc::log::MessageID DHCP6_LEASE_QUERY_PACKET_UNPACK_FAILED
const isc::log::MessageID DHCP4_LEASE_QUERY_PROCESS_FAILED
const isc::log::MessageID DHCP4_LEASE_QUERY_PACKET_UNPACK_FAILED
const isc::log::MessageID DHCP6_LEASE_QUERY_PROCESS_FAILED
isc::log::Logger lease_query_logger("lease-query-hooks")
const isc::log::MessageID DHCP6_LEASE_QUERY_RECEIVED
const int DBGLVL_TRACE_BASIC
Trace basic operations.
Defines the logger used by the top-level component of kea-lfc.
Tag used to access index by object type.