Kea 3.3.1
bulk_lease_query4.cc
Go to the documentation of this file.
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#include <config.h>
8
9#include <dhcp/dhcp4.h>
10#include <dhcp/libdhcp++.h>
11#include <dhcp/pkt4.h>
12#include <dhcp/option_custom.h>
13#include <dhcp/option_int.h>
14#include <dhcpsrv/cfgmgr.h>
16#include <bulk_lease_query4.h>
17#include <lease_query_impl4.h>
18#include <lease_query_log.h>
19#include <blq_service.h>
20#include <stats/stats_mgr.h>
21#include <util/encode/encode.h>
22
23#include <boost/shared_ptr.hpp>
24#include <boost/pointer_cast.hpp>
25
26using namespace isc;
27using namespace isc::asiolink;
28using namespace isc::data;
29using namespace isc::dhcp;
30using namespace isc::lease_query;
31using namespace isc::log;
32using namespace isc::stats;
33
34std::string
36 switch (status) {
38 return ("Success");
40 return ("UnspecFail");
42 return ("QueryTerminated");
44 return ("MalformedQuery");
46 return ("NotAllowed");
47 default:
48 return ("(unknown status code)");
49 }
50}
51
52std::string
54 switch (state) {
56 return ("AVAILABLE");
58 return ("ACTIVE");
60 return ("EXPIRED");
62 return ("RELEASED");
64 return ("ABANDONED");
65 case BLQ_STATE_RESET:
66 return ("RESET");
68 return ("REMOTE");
70 return ("TRANSITIONING");
71 default:
72 return ("(unknown state)");
73 }
74}
75
76std::string
78 Pkt4Ptr pkt = boost::dynamic_pointer_cast<Pkt4>(msg->getPkt());
79 if (!pkt) {
80 return ("<none>");
81 }
83}
84
85void
87 // Take the page size from the MT LQ listener manager.
88 auto service = BulkLeaseQueryService::instance();
89 if (service) {
90 page_size_ = service->getMaxLeasePerFetch();
91 }
92
93 query4_ = boost::dynamic_pointer_cast<Pkt4>(query_->getQuery());
94 if (!query4_) {
95 // Shouldn't happen
96 isc_throw(BadValue, "BulkLeaseQuery4 has no DHCPv4 query");
97 }
98
99 // Check addresses.
100 if (!query4_->getCiaddr().isV4Zero()) {
101 sendDone(BLQ_STATUS_MalformedQuery, "ciaddr must be zero");
102 return;
103 }
104 if (!query4_->getYiaddr().isV4Zero()) {
105 sendDone(BLQ_STATUS_MalformedQuery, "yiaddr must be zero");
106 return;
107 }
108 if (!query4_->getSiaddr().isV4Zero()) {
109 sendDone(BLQ_STATUS_MalformedQuery, "siaddr must be zero");
110 return;
111 }
112
113 // Get the client identifier.
115 if (query_client_id_) {
116 try {
117 ClientId client_id(query_client_id_->getData());
118 } catch (const Exception&) {
119 sendDone(BLQ_STATUS_MalformedQuery, "bad client id option");
120 return;
121 }
122 query_mask_ |= 1;
123 }
124
125 // Get the hardware address.
126 query_hwaddr_ = query4_->getHWAddr();
127 // Ignore the htype.
128 if (query_hwaddr_->hwaddr_.size()) {
129 query_mask_ |= 2;
130 }
131
132 // Get the RAI.
133 OptionPtr rai = query4_->getOption(DHO_DHCP_AGENT_OPTIONS);
134
135 // Get the relay identifier.
136 if (rai) {
137 query_relay_id_ = rai->getOption(RAI_OPTION_RELAY_ID);
138 if (query_relay_id_) {
139 if (query_relay_id_->getData().empty()) {
140 sendDone(BLQ_STATUS_MalformedQuery, "empty relay id option");
141 return;
142 }
143 query_mask_ |= 4;
144 }
145 }
146
147 // Get the remote identifier.
148 if (rai) {
149 query_remote_id_ = rai->getOption(RAI_OPTION_REMOTE_ID);
150 if (query_remote_id_) {
151 if (query_remote_id_->getData().empty()) {
152 sendDone(BLQ_STATUS_MalformedQuery, "empty remote id option");
153 return;
154 }
155 query_mask_ |= 8;
156 }
157 }
158
159 // Get the query start time.
160 OptionPtr opt = query4_->getOption(DHO_QUERY_START_TIME);
161 if (opt) {
162 OptionUint32Ptr qst =
163 boost::dynamic_pointer_cast<OptionInt<uint32_t>>(opt);
164 if (qst) {
165 query_start_time_ = qst->getValue();
166 }
167 if (!qst || (static_cast<int32_t>(query_start_time_) < 0)) {
168 sendDone(BLQ_STATUS_MalformedQuery, "illegal 'query-start-time'");
169 return;
170 }
171 }
172
173 // Get the query end time.
174 opt = query4_->getOption(DHO_QUERY_END_TIME);
175 if (opt) {
176 OptionUint32Ptr qst =
177 boost::dynamic_pointer_cast<OptionInt<uint32_t>>(opt);
178 if (qst) {
179 query_end_time_ = qst->getValue();
180 }
181 if (!qst || (static_cast<int32_t>(query_end_time_) < 0)) {
182 sendDone(BLQ_STATUS_MalformedQuery, "illegal 'query-end-time'");
183 return;
184 }
185 }
186 if ((query_start_time_ > 0) && (query_end_time_ > 0) &&
188 sendDone(BLQ_STATUS_MalformedQuery, "query-start-time > query-end-time");
189 return;
190 }
191
192 // Get the VPN-ID.
193 opt = query4_->getOption(DHO_VSS);
194 if (opt) {
195 sendDone(BLQ_STATUS_NotAllowed, "VPNs are not supported");
196 return;
197 }
198
199 // Do the query based on which query attribute we have,
200 // or error out.
201 switch (query_mask_) {
202 case 0:
203 // Query for all configured addresses (not implemented).
205 "query for all configured addresses is not supported");
206 return;
207
208 case 1:
209 case 2:
210 case 4:
211 case 8:
212 // Supported query by something.
213 return;
214
215 default:
216 // Multiple query types.
217 sendDone(BLQ_STATUS_MalformedQuery, "multiple queries");
218 return;
219
220 }
221}
222
223void
225 if (started_) {
226 isc_throw(InvalidOperation, "BulkLeaseQuery4 already in progress");
227 }
228 started_ = true;
229
230 switch (query_mask_) {
231 case 1:
232 // Query by client id.
234 return;
235 case 2:
236 // Query by hardware addr.
238 return;
239 case 4:
240 // Query by relay id.
242 return;
243 case 8:
244 // Query by remote id.
246 return;
247 default:
248 isc_throw(InvalidOperation, "unknown query-type");
249 }
250}
251
252void
254 if (!query_client_id_) {
255 isc_throw(InvalidOperation, "no query client id");
256 }
257
258 // Fetch leases.
259 ClientId client_id(query_client_id_->getData());
261
262 // Send responses.
263 for (auto const& lease : leases) {
264 if (lease->state_ != Lease::STATE_DEFAULT) {
265 // Not active.
266 continue;
267 }
268 if (lease->expired()) {
269 // Already expired.
270 continue;
271 }
272 if ((query_start_time_ > 0) && (lease->cltt_ < query_start_time_)) {
273 // Too old.
274 continue;
275 }
276 if ((query_end_time_ > 0) && (lease->cltt_ > query_end_time_)) {
277 // Too young.
278 continue;
279 }
280
281 // Send response.
282 sendActive(lease);
283 }
284
285 // Send the done message.
287}
288
289void
291 if (!query_hwaddr_) {
292 isc_throw(InvalidOperation, "no query hardware addr");
293 }
294
295 Lease4Collection leases =
297
298 // Send responses.
299 for (auto const& lease : leases) {
300 if (lease->state_ != Lease::STATE_DEFAULT) {
301 // Not active.
302 continue;
303 }
304 if (lease->expired()) {
305 // Already expired.
306 continue;
307 }
308 if ((query_start_time_ > 0) && (lease->cltt_ < query_start_time_)) {
309 // Too old.
310 continue;
311 }
312 if ((query_end_time_ > 0) && (lease->cltt_ > query_end_time_)) {
313 // Too young.
314 continue;
315 }
316
317 // Send response.
318 sendActive(lease);
319 }
320
321 // Send the done message.
323}
324
325void
327 if (!query_relay_id_) {
328 isc_throw(InvalidOperation, "no query relay id");
329 }
330
331 auto const& relay_id = query_relay_id_->getData();
332 Lease4Collection leases;
333
334 // Database possible call: check if the hook was terminated.
336
337 leases =
343 // when empty it is done.
344 if (leases.empty()) {
346 return;
347 }
348
349 // Record the last address to restart from this point.
350 start_addr_ = leases.back()->addr_;
351
352 // Send responses.
353 for (auto const& lease : leases) {
354 if (lease->state_ != Lease::STATE_DEFAULT) {
355 // Not active.
356 continue;
357 }
358 if (lease->expired()) {
359 // Already expired.
360 continue;
361 }
362
363 // Send response.
364 sendActive(lease);
365 }
366
368 boost::static_pointer_cast<BulkLeaseQuery4>(shared_from_this())));
369}
370
371void
373 if (!query_remote_id_) {
374 isc_throw(InvalidOperation, "no query remote id");
375 }
376
377 auto const& remote_id = query_remote_id_->getData();
378 Lease4Collection leases;
379
380 // Database possible call: check if the hook was terminated.
382
383 leases =
389 // when empty it is done.
390 if (leases.empty()) {
392 return;
393 }
394
395 // Record the last address to restart from this point.
396 start_addr_ = leases.back()->addr_;
397
398 // Send responses.
399 for (auto const& lease : leases) {
400 if (lease->state_ != Lease::STATE_DEFAULT) {
401 // Not active.
402 continue;
403 }
404 if (lease->expired()) {
405 // Already expired.
406 continue;
407 }
408
409 // Send response.
410 sendActive(lease);
411 }
412
414 boost::static_pointer_cast<BulkLeaseQuery4>(shared_from_this())));
415}
416
417void
420
421 // Add the dhcp-server-identifier in the first response.
422 if (sent_ == 0) {
425 auto const& srv = BulkLeaseQueryService::instance();
426 if (!srv) {
427 isc_throw(Unexpected, "can't find bulk lease query service");
428 }
429 opt->writeAddress(srv->getLeaseQueryIp());
430 response->addOption(opt);
431 }
432 ++sent_;
433
434 // Send it.
435 BlqResponsePtr resp(new BlqResponse(response));
436 if (!push_to_send_(resp)) {
437 isc_throw(QueryTerminated, "connection closed");
438 }
439}
440
441void
442BulkLeaseQuery4::sendDone(BLQStatusCode status, const std::string& message) {
443 // Create and send done message.
444 Pkt4Ptr done(new Pkt4(DHCPLEASEQUERYDONE, query4_->getTransid()));
445
446 // Zero out the hwaddr type.
447 done->setHWAddr(HWAddrPtr(new HWAddr(std::vector<uint8_t>{}, 0)));
448
449 // Add the status.
450 if ((status != BLQ_STATUS_Success) || !message.empty()) {
453 opt->writeInteger(static_cast<uint8_t>(status), 0);
454 opt->writeString(message, 1);
455 done->addOption(opt);
456 }
457
458 // Send it.
459 send(done);
460
461 // It is final.
462 setDone();
463}
464
465void
467 // Should not happen.
468 if (!lease) {
469 return;
470 }
471
472 // Get subnet.
474 ->getCfgSubnets4()->getSubnet(lease->subnet_id_);
475 if (!subnet) {
476 // Should not happen: simply ignore this lease.
477 return;
478 }
479
480 // Create and send active message.
481 Pkt4Ptr active(new Pkt4(DHCPLEASEACTIVE, query4_->getTransid()));
482
483 // Add client IP address.
484 active->setCiaddr(lease->addr_);
485
486 // Add client hardware address.
487 if (lease->hwaddr_) {
488 active->setHWAddr(lease->hwaddr_);
489 } else {
490 active->setHWAddr(HWAddrPtr(new HWAddr(std::vector<uint8_t>{}, 0)));
491 }
492
493 // Add client identifier.
494 if (lease->client_id_) {
496 lease->client_id_->getClientId()));
497 active->addOption(opt);
498 }
499
500 // Add base time.
502 active->addOption(opt);
503
504 // Add lease life time, T1 and T2.
505 LeaseQueryImpl4::addLeaseTimes(active, lease, subnet);
506
507 // Add relay-agent-info (82) from the extended info in the lease's
508 // user-context and add it to the response.
510
511 // Send it.
512 send(active);
513}
std::string getStateName(BLQStates state)
std::string getStatusCodeName(BLQStatusCode status)
#define DHO_VSS
Virtual Subnet Selection Option code point (RFC 6607 and 6926).
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
A generic exception that is thrown if a function is called in a prohibited way.
A generic exception that is thrown when an unexpected error condition occurs.
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
Holds Client identifier or client IPv4 address.
Definition duid.h:222
static TrackingLeaseMgr & instance()
Return current lease manager.
virtual Lease4Collection getLeases4ByRemoteId(const OptionBuffer &remote_id, const asiolink::IOAddress &lower_bound_address, const LeasePageSize &page_size, const time_t &qry_start_time=0, const time_t &qry_end_time=0)=0
Returns existing IPv4 leases with a given remote-id.
virtual Lease4Collection getLeases4ByRelayId(const OptionBuffer &relay_id, const asiolink::IOAddress &lower_bound_address, const LeasePageSize &page_size, const time_t &qry_start_time=0, const time_t &qry_end_time=0)=0
Returns existing IPv4 leases with a given relay-id.
virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress &addr) const =0
Returns an IPv4 lease for specified IPv4 address.
Wraps value holding size of the page with leases.
Definition lease_mgr.h:46
static const OptionDefinition & DHO_DHCP_SERVER_IDENTIFIER_DEF()
Get definition of DHO_DHCP_SERVER_IDENTIFIER option.
static const OptionDefinition & DHO_STATUS_CODE_DEF()
Get definition of DHO_STATUS_CODE option.
Option with defined data fields represented as buffers that can be accessed using data field index.
Base class representing a DHCP option definition.
Represents DHCPv4 packet.
Definition pkt4.h:37
Holds a bulk lease query response packet.
Definition blq_msg.h:124
dhcp::HWAddrPtr query_hwaddr_
The query hardware address (for a by hardware address bulk query).
void bulkQueryByClientId()
Start processing of a by client id bulk query.
size_t sent_
Sent response counter.
virtual void start()
Start processing.
time_t query_start_time_
The query start time.
time_t query_end_time_
The query end time.
virtual void send(dhcp::Pkt4Ptr response)
Send a response.
static std::string leaseQueryLabel(const BlqMsgPtr &msg)
Convenience method for generating per packet logging info.
static void doBulkQueryByRemoteId(BulkLeaseQuery4Ptr ptr)
Class/static subsequent processing of a by remote id bulk query.
void bulkQueryByRelayId()
Start processing of a by relay id bulk query.
dhcp::OptionPtr query_client_id_
The query client id (for a by client id bulk query).
asiolink::IOAddress start_addr_
The start address (for paged processing).
void bulkQueryByHWAddr()
Start processing of a by harware address bulk query.
size_t page_size_
The page size (for paged processing, taken from the MT Lease query manager or defaults to 10).
dhcp::OptionPtr query_remote_id_
The remote id (for a by remote id bulk query).
virtual void sendDone(BLQStatusCode status, const std::string &message="")
Send a DHCPLEASEQUERYDONE message.
dhcp::OptionPtr query_relay_id_
The query relay id (for a by relay id bulk query).
static void doBulkQueryByRelayId(BulkLeaseQuery4Ptr ptr)
Class/static subsequent processing of a by relay id bulk query.
dhcp::Pkt4Ptr query4_
The DHCPv4 query.
void bulkQueryByRemoteId()
Start processing of a by remote id bulk query.
virtual void sendActive(const dhcp::Lease4Ptr &lease)
Send a DHCPLEASEACTIVE message.
virtual void init()
Initialization.
static BulkLeaseQueryServicePtr instance()
Returns a pointer to the sole instance of the BulkLeaseQueryService, can return null.
virtual void setDone()
Set the done flag.
BlqPostCb post_
The post callback.
bool started_
The processing is in progress.
BlqPushToSendCb push_to_send_
The pushToSend callback.
static void addLeaseTimes(dhcp::Pkt4Ptr response, const dhcp::Lease4Ptr &lease, const dhcp::Subnet4Ptr &subnet)
Adds life time, T1, and T2 options to a query response.
static std::string leaseQueryLabel(const dhcp::Pkt4Ptr &packet)
Convenience method for generating per packet logging info.
static void addRelayAgentInfo(dhcp::Pkt4Ptr response, const dhcp::Lease4Ptr &lease)
Adds relay-agent-info option to a query response.
Thrown on hook termination.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
OptionInt< uint32_t > OptionUint32
Definition option_int.h:34
boost::shared_ptr< OptionUint32 > OptionUint32Ptr
Definition option_int.h:35
#define CHECK_TERMINATED
boost::shared_ptr< Subnet4 > Subnet4Ptr
A pointer to a Subnet4 object.
Definition subnet.h:458
@ DHO_QUERY_START_TIME
Definition dhcp4.h:208
@ DHO_DHCP_CLIENT_IDENTIFIER
Definition dhcp4.h:130
@ DHO_BASE_TIME
Definition dhcp4.h:206
@ DHO_QUERY_END_TIME
Definition dhcp4.h:209
@ DHO_DHCP_AGENT_OPTIONS
Definition dhcp4.h:151
boost::shared_ptr< OptionCustom > OptionCustomPtr
A pointer to the OptionCustom object.
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition pkt4.h:556
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition hwaddr.h:154
@ DHCPLEASEQUERYDONE
Definition dhcp4.h:249
@ DHCPLEASEACTIVE
Definition dhcp4.h:247
@ RAI_OPTION_RELAY_ID
Definition dhcp4.h:276
@ RAI_OPTION_REMOTE_ID
Definition dhcp4.h:266
std::vector< Lease4Ptr > Lease4Collection
A collection of IPv4 leases.
Definition lease.h:520
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition lease.h:315
boost::shared_ptr< Option > OptionPtr
Definition option.h:37
boost::shared_ptr< BlqResponse > BlqResponsePtr
Defines a shared pointer to an BlqResponse.
Definition blq_msg.h:143
BLQStatusCode
Status Codes.
boost::shared_ptr< BlqMsg > BlqMsgPtr
Defines a shared pointer to an BlqMsg.
Definition blq_msg.h:93
Defines the logger used by the top-level component of kea-lfc.
Hardware type that represents information from DHCPv4 packet.
Definition hwaddr.h:20
static constexpr uint32_t STATE_DEFAULT
A lease in the default state.
Definition lease.h:69